Swiftの `_` (アンダースコア)

Swiftの `_` (アンダースコア)の絡んだネタをいくつか書いてみます。

# 戻り値を `_` で受けて破棄

Swift 3では、以下のように書くと、`Result of call to 'f()' is unused`という警告が発生します。

```swift
func f() -> String {
    return ""
}
f()
```
(※Playgroundでは戻り値が評価されて右のエリアに表示されるようになっているため警告は発生しません。実コード上での確認が必要です。その他、Playgroundの動作はたまに怪しいことがあるので違和感あった際も同様の確認をお勧めします。)

次のように`_`で受けると警告が消えます。

```swift
_ = f()
```

あまり慣れていないと、次のように書くのが普通な気がしてしまいますが、`_`は特別扱いされていて、`let`は省略可能です。(すでに`var _`で宣言済みの変数に入れて葬るイメージ？)
無くても良いものは書かない方が良い(書いたメリットが明確な場合は別として)と思っているので、基本上の書き方が良いと思っています。

```swift
let _ = f()
```

他の言語では規約ベースで`_`や`_`で始まる識別子で受けて不使用であったりプライベートなものであることの目印にすることが多くて(後者はSwiftでもまあまあやると思いますが)、これが言語仕様に含まれているのはより確実なコードが書きやすくてありがたいです。

また、以下のように何回でも使えます。

```swift
_ = f()
_ = f()
```

破棄用なので、次のように書くと、`error: '_' can only appear in a pattern or on the left side of an assignment`というコンパイルエラーが発生します。

```swift
print(_)
```

> “An underscore (_) parameter is explicitly ignored and can’t be accessed within the body of the function.”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 3).” iBooks. https://itun.es/jp/jEUH0.l

もちろん、通常の識別子を使った場合は以下のようにすると2つ目でコンパイルエラー発生します。

```swift
let x = f()
let x = f()
```

ちょっと蛇足ですが、Swiftはスコープがネストされれば同じ識別子使えたりします。
特に静的言語の中ではこう書ける言語少数派な気がします。
下の例はややこしくなってあまり良くない例ですが、このおかげで書きやすい場面は多く、個人的には気に入っている仕様です。


```swift
let 🍎 = "りんご"
do {
    let 🍎 = "リンゴ"
    print(🍎) // リンゴ
}
print(🍎) // りんご
```

## 戻り値不使用のケースの別解(`@discardableResult`)

Swift 3では、次のように`@discardableResult`を関数定義に添えると、戻り値不使用でも警告が発生しなくなります。

```swift
@discardableResult func f() -> String {
    return ""
}
f()
```

Swift 2では、デフォルトでは戻り値不使用でも警告は発生せず、`@warn_unused_result`を添えると警告が発生する、という逆の挙動でした。
プログラマーのうっかりミスを防ぎやすくなるので、Swift 3の方が良いですね。
参考: [swift-evolution/0047-nonvoid-warn.md at master · apple/swift-evolution](https://github.com/apple/swift-evolution/blob/master/proposals/0047-nonvoid-warn.md)

こういった警告は、特に以下のケースで、Bのように`sort`を使うべきなのにうっかりAの`sorted`を使ってしまい戻り値を受け取らなかった時にそのミスに気付けて素晴らしいです。

```swift
var array = [2, 3, 1]
// A: array自体はそのままで、戻り値が [1, 2, 3]となる。戻り値を受けてないので警告発生。
array.sorted() 
// B: array自体を[1, 2, 3]に変更
array.sort() 
```

好きな方使えば良いというわけではなく、自身で定義しているなどで書き換え可能かつ戻り値を破棄しても通常問題無いものであるケースのみ、`@discardableResult`を添えて定義して、それ以外は利用箇所にて個別に`_`で受けて破棄、というのが良いと思っています。

# 不使用変数を `_` で隠す

上の話と似てますが、`_`で不使用変数を隠すこともよくします。

こういう関数があったとして、`やあ(　´･‿･｀)`のようなどうでも良い値が渡ってきても不要なので破棄したいとします。

```swift
func f2(closure: (String) -> ()) {
    closure("やあ(　´･‿･｀)")
}
```

この場合は、こう書いても`str`が不使用と怒られることはありませんので、このままでも特に問題ありません。

```swift
f2 { str in
}
```

ただ、間違えて`str`の値を使ってしまうミスを確実に防ぎたい場合は、次のように`_`で受けると良いです。

```swift
f2 { _ in
    // `print(_)`ももちろん不可能
}
```

しかし、あとでやはり使おうとなった時にどのような値が来ているのかの情報が失われて定義を再確認するなど(特にパラメータの数が多いなど複雑な時)、必ずしも良いことばかりでも無いため、以下のように`_str`など`_`始まりとして何となく不使用ということを明示するだけにとどめておくパターンもあります。
この場合、単なる規約ベースのやり方なので、うっかり使ってしまうミスは防げませんので、状況によりけりですね。

```swift
f2 { _str in
    // `print(_str)`と書くと`やあ(　´･‿･｀)`と出力されてしまう
}
```

# `_`で区切って数値を見やすく

このように、任意の桁に`_`を挟むことで、見やすく出来ます。

```swift
let intMax = 2_147_483_647
```

挿入箇所も数も自由なので、このようにして見づらく嫌がらせすることも出来ます(　´･‿･｀)

```swift
let intMax = 2_147_483________________________________________________________________________________________________________________________________________________________________647
```

コード上の見た目だけの違いで、扱いは `let intMax = 2147483647` と書いた時と全く同じです。
> “Underscores (_) are allowed between digits for readability, but they are ignored and therefore don’t affect the value of the literal. Integer literals can begin with leading zeros (0), but they are likewise ignored and don’t affect the base or value of the literal.”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 3).” iBooks. https://itun.es/jp/jEUH0.l

この書き方に対応した言語は少なめな印象でしたが、最近は増えてきています。

- Ruby: 対応
- Python: 3.5までは非対応
    - 3.6で入った(`_`を2つ以上連続させることはできない)
- Go: 非対応
- C#: 6までは非対応
    - 7で入る予定(http://ufcpp.net/study/csharp/start/stnumber/#digit-separator)

# 引数ラベルの省略

こちらは特に当たり前に使っていると思いますが、以下の時に`value`ラベルを省略したい場合は、

```swift
func f3(value: Int) {
}
f3(value: 1)
```

次のように書きます。

```swift
func f3(_ value: Int) {
}
f3(1)
```

ラベル付きの方は、以下のショートハンドと捉えると`_`を指定した時の挙動が理解しやすいですね。
(以下はラベルとパラメーター名を別にしたい時の使い方なのでこのように同名の場合は、`Extraneous duplicate parameter name; 'value' already has an argument label`という警告が発生しますが)

```swift
func f3(value value: Int) {
}
f3(value: 1)
```

そういえば、Swift 2まではラベル周りの挙動がちぐはぐでしたが、Swift 3で解消されて良かったですね。
[swift-evolution/0046-first-label.md at master · apple/swift-evolution](https://github.com/apple/swift-evolution/blob/master/proposals/0046-first-label.md)

---

他にも破棄したい場合の細かい使い方がありますが、本質的に同じなので省略します。

[The Swift Programming Language (Swift 3.0.1) by Apple Inc. on iBooks](https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11)で`underscore`で検索すると、利用例や仕様についての記載を確認出来ます。

`_`について書いてて連想しましたが、`$`もちょっと特別な感じになる予定です。
[swift-evolution/0144-allow-single-dollar-sign-as-valid-identifier.md at master · apple/swift-evolution](https://github.com/apple/swift-evolution/blob/master/proposals/0144-allow-single-dollar-sign-as-valid-identifier.md)

こちらについては [🎃Swiftレター #5🎃 – Swift・iOSコラム – Medium](https://medium.com/swift-column/issue5-e081d996b099#.ftgtsqgyz) に書いたので興味あればご覧ください。