LoginSignup
3
2

More than 5 years have passed since last update.

[Swift] 名前が衝突したときに呼び出すグローバル関数を明示する

Posted at

TL;DR

モジュール名.グローバル関数名で呼び出せる。(標準のモジュール名はSwift

Swift.min(1, 2) // => 1
Foo.bar() // Note: Foo is framework

Swift 3.0 でのAPI名変更

Swift 3.0 では標準ライブラリのAPI名がガイドラインに沿って見直しがされました。
例えばSequenceType.minElement().min()へと変更されています。

これは大した話ではないと感じますが、以下のコードがコンパイルエラーになります。

extension Array {
    func foo() {
        let x = min(1, 2) // Compile error: Extra argument in call
        print("x: \(x)")
    }
}

上記はグローバル関数のmin()を呼び出すつもりが、SequenceType.min()が名前解決されてしまい、意図しない関数が呼び出されてしまっています。

このように名前空間が衝突した場合に、グローバル関数を明示的に呼び出すには以下のように頭にSwift.を追加すればOKです。

extension Array {
    func foo() {
        let x = Swift.min(1, 2) // OK
        print("x: \(x)")
    }
}

同様に、Fooモジュールのbar()という関数を呼び出す場合には以下のようにすればOKです。

Foo.bar()

グローバル関数が重複した場合

さきほどの例ではArrayのextensionにおいて、SequenceTypeの関数とグローバル関数の名前が衝突し、前者のほうが意図した呼び出しだと名前解決されました。

では、グローバル関数がモジュール間で重複した場合はどうなるのでしょうか?

(おそらく想像通りかと思いますが)結論から言えば、自身のモジュール内の関数が優先して名前解決されます。

// モジュール(プロジェクト)`Hello`に宣言されたグローバル関数
func bar() -> String {
    return "bar in Hello"
}

// モジュール`Foo`に宣言されたグローバル関数
public func bar() -> String {
    return "bar in Foo"
}

// `Hello`内でのコード
bar()       // => bar in Hello
Hello.bar() // => bar in Hello
Foo.bar()   // => bar in Foo

ここまで説明の都合上、グローバル関数を例に上げましたが、グローバル定数などのグローバルシンボルについても同様です。

let FOO_BAR:        String = "FOO_BAR in Hello"
public let FOO_BAR: String = "FOO_BAR in Foo"

FOO_BAR       // => FOO_BAR in Hello
Hello.FOO_BAR // => FOO_BAR in Hello
Foo.FOO_BAR   // => FOO_BAR in Foo

まとめ

  • 明示的にグローバルシンボルにアクセスする場合はモジュール名.シンボル名と書く
  • Swift標準のモジュール名はSwift
  • 名前解決は自身に近い位置から行われていく

蛇足

冒頭にあげたArrayのextensionのケースでコンパイルエラーになって「なんで?」って躓いたので、他にも躓く人がいるかもと思って書いてみました。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2