SwiftUI.TextにIntが変数展開されたStringを渡すと3桁区切りになる

![スクリーンショット 2021-06-28 20.58.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/9d4eee9f-e43c-db8d-d4c2-cf9bfb69c245.png)

いったいどうなってるんだってばよ！！

```swift
print(String(1234))
// -> 1234
print("\(1234)")
// -> 1234
```

もちろん、普通に変数展開されたStringをprintしても3桁区切りにはなりません。

![スクリーンショット 2021-06-28 21.01.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/6841014b-ca7d-388d-dd1c-45755e488c0c.png)

どうやら、変数展開している箇所にこの不思議な挙動の秘密がありそうです。

## この挙動は一体なんなのか
調べてみたところ、こちらの記事に出会いました。すごくよくまとまっていて、Int以外の変数展開についても書かれているのでぜひこちらも見てみてください。(Textの変数展開にImageや別のText入れられるの知らなかった...)

https://qiita.com/ensan_hcl/items/d9b0fdadec8ca77a556c


要約すると

- SwiftUI.Textはイニシャライザの引数として `LocalizedStringKey` を受け取る
- `LocalizedStringKey` は `ExpressibleByStringInterpolation` に準拠する型で、 `StringInterpolationProtocol` に準拠した型 `StringInterpolation` を内部的に持っている
- SwiftUI　は `LocalizedStringKey.StringInterpolation` を拡張した `appendInterpolation` を定義することで、カスタマイズされた変数展開が利用できるようになっている

このような実装によって、カスタマイズされた変数展開ができるようになっています。

## その上で今回の挙動について紹介

SwiftUIに定義されている `appendInterpolation` には `public mutating func appendInterpolation<T>(_ value: T) where T : _FormatSpecifiable` というメソッドがあり、今回の挙動はこれが関係しています。

```swift
public protocol _FormatSpecifiable : Swift.Equatable {
    associatedtype _Arg : Swift.CVarArg
    var _arg: Self._Arg { get }
    var _specifier: Swift.String { get }
}
```

`_FormatSpecifiable` の定義は上のようになっていて

```swift
extension Int : SwiftUI._FormatSpecifiable
extension Int8 : SwiftUI._FormatSpecifiable
extension Int16 : SwiftUI._FormatSpecifiable
extension Int32 : SwiftUI._FormatSpecifiable
extension Int64 : SwiftUI._FormatSpecifiable
extension UInt : SwiftUI._FormatSpecifiable
extension UInt8 : SwiftUI._FormatSpecifiable
extension UInt16 : SwiftUI._FormatSpecifiable
extension UInt32 : SwiftUI._FormatSpecifiable
extension UInt64 : SwiftUI._FormatSpecifiable
extension Float : SwiftUI._FormatSpecifiable
extension Double : SwiftUI._FormatSpecifiable
extension CGFloat : SwiftUI._FormatSpecifiable
```

`Int` や `Double` などの数値型が `_FormatSpecifiable` に準拠していることがわかります。

ちなみに、Doubleを渡すと

![スクリーンショット 2021-06-28 21.59.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/f2262bf6-5fc0-ad42-37da-448fbc877f93.png)

`%.6f` 相当のフォーマットがされていて、フォーマットのされ方も数値型によって違っているようです。

この `_FormatSpecifiable` を拡張した実装の中身までは確認できなかったのですが、 `appendInterpolation` には他にも `public mutating func appendInterpolation<T>(_ value: T, specifier: String) where T : _FormatSpecifiable` メソッドが生えてきて、

![スクリーンショット 2021-06-28 21.57.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84888/fc06ed55-295e-7038-6dbe-787225f6e9d1.png)

のような使い方ができるため、各種の数値型に対して上のような文字列フォーマット指定子が `_specifier` でそれぞれ設定されているのだと思われます。


## 参考資料

- [LocalizedStringKey.StringInterpolation | Apple Developer Documentation](https://developer.apple.com/documentation/swiftui/localizedstringkey/stringinterpolation)
- [[Swift] SwiftUIの不思議な機能を実現する変数展開"\()"について調べた | Qiita](https://qiita.com/ensan_hcl/items/d9b0fdadec8ca77a556c)
- [Localize Interpolated String: Why Only String Value Work? | Swift Forums](https://forums.swift.org/t/localize-interpolated-string-why-only-string-value-work/27528/11)