"\(foo)"
の実装がどうなるのか見た https://github.com/apple/swift/blob/87df9961a5c8ec5f6db11ae2587c13ae57ac1bd4/stdlib/public/core/StringInterpolation.swift<T>
5. Any.Type
の場合 の5つのオーバーロードがあるっぽい_print_unlocked
っていう謎の関数に転送されていてString.init<T>(describing: T)
の実装も、 _print_unlocked
への転送だった。_print_unlocked
の実装は結構面白くて_openExistential
を使ってる if _openExistential(type(of: value as Any), do: _isOptional) { let debugPrintable = value as! CustomDebugStringConvertible debugPrintable.debugDescription.write(to: &target) return }
<T>
を受けるので必ずopenできるがその先でoptionalかチェックするから、これでAnyの中に入ってるOptionalとかをおそらく必ず展開できて、 OptionalだからCustomDebugStringConvertibleが通るMirror(reflecting: value)
foo
はオプショナルの場合の fix-itが2つ出るが、片方は、 String(describing: foo)
への書き換えだから、 String.init(describing:)
の実装と 4の実装が同じ( _print_unlocked
)なのは暗黙的な規約っぽい。_print_unlocked
は第二引数でStreamを取れるけどstdlib internalなので、 これはユーザーに提供されていない事になる。 String.init(describing:)
を使ってエミュレートできるけど、ストリーム処理可能な場合にパフォーマンスロスが出ちゃう。