1. ホーム
  2. swift

[解決済み] なぜswiftではアンダースコアが必要なのですか?

2022-02-28 04:08:07

質問

これ と書かれています。 _ は、「その値にはこだわらない」という意味なのだが、JavaScript出身の私にはその意味がわからない。

これらの関数を表示させる唯一の方法は、パラメータの前にアンダースコアを使用することでした。

func divmod(_ a: Int, _ b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(7, 3))
print(divmod(5, 2))
print(divmod(12,4))

アンダースコアがない場合は、このように書かないとエラーになります。

func divmod(a: Int, b:Int) -> (Int, Int) {
    return (a / b, a % b)
}

print(divmod(a: 7, b: 3))
print(divmod(a: 5, b: 2))
print(divmod(a: 12,b: 4))

このアンダースコアの使い方がよくわかりません。いつ、どのように、なぜ、このアンダースコアを使うのでしょうか?

どのように解決するのですか?

使用例によって多少のニュアンスの違いはありますが、一般的にアンダースコアは "これを無視してください" を意味します。


新しい関数を宣言するとき、アンダースコアは、パラメータが呼び出されたときにラベルを持たないようにSwiftに伝えます - あなたが見ているのはそのケースです。より完全な関数宣言は、次のようになります。

func myFunc(label name: Int) // call it like myFunc(label: 3)

"label"は引数のラベルで、関数を呼び出すときに存在する必要があります。(そして、Swift 3以降、ラベルはデフォルトですべての引数のために必要です。) "name"は関数内で使用するその引数のための変数の名前です。より短い形式は次のようになります。

func myFunc(name: Int) // call it like myFunc(name: 3)

これは、外部引数ラベルと内部パラメータ名の両方に同じ単語を使用できるようにするショートカットです。これは次のように等価です。 func myFunc(name name: Int) .

パラメータ・ラベルなしで関数を呼び出したい場合は、アンダースコアの _ を使えば、ラベルを無/無視することができます。(この場合、パラメータを使用できるようにするには、内部名を指定する必要があります)。

func myFunc(_ name: Int) // call it like myFunc(3)


代入文において、アンダースコアは「何も代入しない」という意味です。結果を返す関数を呼び出したいけど、返された値にはこだわらないという場合に使います。

_ = someFunction()

あるいは、リンク先の記事のように、返されたタプルの1つの要素を無視することです。

let (x, _) = someFunctionThatReturnsXandY()


ある定義された関数型を実装するクロージャを書くとき、アンダースコアを使って特定のパラメータを無視することができます。

PHPhotoLibrary.performChanges( { /* some changes */ },
    completionHandler: { success, _ in // don't care about error
        if success { print("yay") }
    })

同様に、プロトコルを採用する関数や、スーパークラスのメソッドをオーバーライドする関数を宣言する場合にも _ には、パラメータ 名前 でパラメータを無視します。プロトコルやスーパークラスでは、パラメータにラベルをつけないことも定義されているかもしれないので、アンダースコアを2つ並べることも可能です。

class MyView: NSView {
    override func mouseDown(with _: NSEvent) {
        // don't care about event, do same thing for every mouse down
    }
    override func draw(_ _: NSRect) {
        // don't care about dirty rect, always redraw the whole view
    }
}


最後の2つのスタイルと多少関係があります。ローカル変数/定数をバインドするフロー制御のコンストラクトを使用する場合、以下のようになります。 _ を無視することができます。たとえば、シーケンスのメンバにアクセスすることなく、シーケンスを反復処理する場合です。

for _ in 1...20 { // or 0..<20
    // do something 20 times
}


switch文の中でタプルケースを束ねる場合、この例のようにアンダースコアはワイルドカードとして機能します(短縮版は プログラミング言語Swift ):

switch somePoint { // somePoint is an (Int, Int) tuple
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
default:
    print("(\(somePoint.0), \(somePoint.1)) isn't on an axis")
}


最後に、あまり関係ないのですが、(コメントで指摘されているように)ここに誘導されそうなので、載せておきます。アンダースコア 識別子 - 例 var _foo , func do_the_thing() , struct Stuff_ - は、Swift には特に何も意味しませんが、プログラマーの間でいくつかの用途があります。

名前内のアンダースコアはスタイルの選択ですが、Swiftコミュニティでは好まれません。Swiftコミュニティでは、型にはUpperCamelCase、他のすべてのシンボルにはlowerCamelCaseを使用するという強い慣習があります。

シンボル名の前にアンダースコアを付けるのはスタイルコンベンションの一つで、歴史的にはプライベート/内部使用専用のシンボルとエクスポートされたAPIを区別するために使用されました。しかし、Swift にはそのためのアクセス修飾子があるため、一般的にこの規約は Swift では非日常的なものと見なされています。

ダブルアンダースコアのプレフィックスを持ついくつかのシンボル ( func __foo() は、AppleのSDKの奥深くに潜んでいます。を使用して Swift にインポートされた (Obj)C のシンボルです。 NS_REFINED_FOR_SWIFT 属性があります。Appleは、(Obj)CのAPIの"more Swifty"バージョンを作りたいときにこれを使います - 例えば。 型にとらわれないメソッドを汎用的なメソッドにするために . 洗練されたSwiftバージョンを動作させるためにインポートされたAPIを使用する必要があるので __ を使用して、ほとんどのツールやドキュメントから隠しつつ、利用可能な状態を維持します。