構造体を文字列としてみる
struct Hoge { let name:String let age:Int } extension String.StringInterpolation { mutationg func appendInterpolation(_ value: User) { appendInterpolation("Hoge's name is \(value.name) and he name is \(value.age)") } }
としておいて、
let hoge = Hoge(name:"poi", age:44) print("Hoge deatil \(hoge)) /// ここでhogeを引数にとっていることがポイント
これはCustomStringConvertibleと同じである。
しかし、こんなこともできる・
引数を好きなだけとれるのだ
extension String.StringIterpolation { mutating func appendInterpolation(_ number: Int, style:NumberFormatter.Style) { formatter.numberStyle = style if let result = formatter.string(from: number as NSNumber) { appendLiteral(result) } }
これで $20とか、1st, 12thとかできる。
let number = Int.random(in:0...100) let lucky = "lucky number this weeks os \(number, style: .spellOut)." print(lucky)
appendLiteralは必要に応じて何度も呼べる。
extension String.StringInterpolation { mutating func appendInterpolation(repeat str: string, _ count:Int) { for _ in 0..< count { appendLiteral(str) } } } print("say, \(repat: "hello!,", 3)
他のSwiftの機能と組み合わせて例えば配列がないときはデフォルト表示するなどできる。
extension String.StringInterpolation { mutating func appendInterpolation(_ value:[String], empty defaultValue:@autoclosure () -> String) { if value.count == 0 appendLiteral(defaultValue()) } else { appendLiteral(values.joined(separator:",")) } } } let particle = ["fermion", "boson"] print("List of particle: \(names, empty: "No one").") @autoclosureを使うことで単純なあたいや、複雑な関数を呼び出しできる。 ExpressibleByStringLiteralやExpressibleByStringInterpolationなどと組み合わせることで 文字列補間で全体の型を作れるようになり、CustomStringConvertibleを通してその型をprintできるようにさえなった。 必要なことは ExpressibleByStringLiteralとExpressibleByStringInterpolationに準拠することで必要ならCustomStringConvertibleにも準拠すること。 自分の型の中にネストしてStringInterpolation構造体を作りStringInterpolationProtocolに準拠させる。その初期化には期待する大まかなデータ量を入れる必要がある。また、appendLiteral() を実装する必要がある。appendInterpolation()もいる。 初期化も2ついる。 様々な共通エレメントからHTMLを構成する型を例につくろう。
struct HTMLComponent: ExpressibleByStringLiteral, ExpressibleByStringInterpolation, CustomStringConvertible { struct StringInterpolation: StringInterpolationProtocol { // start with an empty string var output = ""
// allocate enough space to hold twice the amount of literal text
init(literalCapacity: Int, interpolationCount: Int) {
output.reserveCapacity(literalCapacity * 2)
}
// a hard-coded piece of text – just add it
mutating func appendLiteral(_ literal: String) {
print("Appending \(literal)")
output.append(literal)
}
// a Twitter username – add it as a link
mutating func appendInterpolation(twitter: String) {
print("Appending \(twitter)")
output.append("<a href=\"https://twitter/\(twitter)\">@\(twitter)</a>")
}
// an email address – add it using mailto
mutating func appendInterpolation(email: String) {
print("Appending \(email)")
output.append("<a href=\"mailto:\(email)\">\(email)</a>")
}
}
// the finished text for this whole component
let description: String
// create an instance from a literal string
init(stringLiteral value: String) {
description = value
}
// create an instance from an interpolated string
init(stringInterpolation: StringInterpolation) {
description = stringInterpolation.output
}
}
let text: HTMLComponent = "You should follow me on Twitter (twitter: "twostraws"), or you can email me at (email: "paul@hackingwithswift.com")." print(text) /// You should follow me on Twitter @twostraws, or you can email me at paul@hackingwithswift.com.
これでHTMLが吐き出されるが、他にも使い方がありそう。 参考文献 [https://github.com/twostraws/whats-new-in-swift-5-0:title]