プロトコルStringInterpolationConvertibleの使いかたがようやくわかったので簡単に紹介します。
StringInterpolationConvertibleとは
String Interpolationとは簡単に言うと、文字列の中の\(コレ)
のことです。
つまり、StringInterpolationConvertibleとは、 String Interpolationを含む文字列をコンバートできるようにしたクラス、ということになります。
StringInterpolationConvertibleプロトコルの実装例
StringInterpolationConvertibleプロトコルの実装すると、次のように数値に16進数を併記させるといったことも可能になります。
print("\(777) is a magical number!" as HexNumberString) //=> "777 (0x309) is a magical number!" print("\(0xdead_beaf), \(UInt(777))" as HexNumberString) //=> "3735928495 (0xDEADBEEF), 777"
実装は次のような感じ (解説は後ほど)。
final class HexNumberString : StringInterpolationConvertible, Printable { let s: String required init<T>(stringInterpolationSegment expr: T) { s = "\(expr)" } required init(stringInterpolationSegment expr: Int) { let hex = String(NSString(format:"%X", expr)) s = "\(expr) (0x\(hex))" } required init(stringInterpolation strings: HexNumberString...) { s = "".join(strings.map { $0.s }) } var description: String { return s } }
StringInterpolationConvertibleプロトコルの処理手順
- 与えられた文字列は、String Interpolationの部分と地の文字列とに分けられます。
- 先頭から順番に
init(stringInterpolationSegment)
が呼ばれて、それぞれのインスタンスが作成されます。 - 作成したインスタンスをまとめた配列で
init(stringInterpolation strings: HexNumberString...)
が呼ばれます
例えば、"abc\(1 + 30)" as HexNumberString
では、まず
String
型の"abc"
- (評価後の)
Int
型の31
String
型の""
の3つに分かれます。
1つめの"abc"
と3つめの""
に対してはinit<T>(stringInterpolationSegment: T)
が呼ばれますが、2つめの31
にはinit(stringInterpolationSegment: Int)
が呼ばれます。
これによって、3つのHexNumberString
型のインスタンス (内部変数s
は順番に"abc"
, "31 (0x1F)"
, ""
) が作成されます。
そして最後に、この3つのインスタンスをまとめた配列を引数として、init(stringInterpolation strings: HexNumberString...)
が呼ばれます。
StringInterpolationConvertibleプロトコルの実装の手引き
汎用型のinit<T>(stringInterpolationSegment: T)
を実装する以外にも、
自分がカスタマイズしたい型をinit(stringInterpolationSegment: SomeClass)
として実装します。
上の例では16進数を表示させたいInt
型について実装しています。
汎用型のinit<T>(stringInterpolationSegment: T)
は地のString
を含むことがあるので何もしないのが無難でしょう。
同様に、init<T>(stringInterpolationSegment: String)
では地のString
を含むことがあるので注意です。
StringInterpolationConvertible
は実装クラスがfinal
でないと次のようなエラーになるのでfinal
しておきます。
Protocol ‘StringInterpolationConvertible’ requirement ‘init(stringInterpolation:)’ cannot be satisfied by a non-final class (‘MySample’) because it uses ‘Self’ in a non-parameter, non-result type position
Printable (Swift 2ではCustomStringConvertible) を実装しないとprint
でクラス名が表示されるだけになるので実装します。
応用編
数値をローマ数字や漢数字に変換するクラスや、次のような比較用タプルが使えるようにしたDiffString
というのも考えられます。
required init<Eq: Equatable>(stringInterpolationSegment expr: (Eq, Eq)) { let cmp = expr.0 == expr.1 ? "==" : "!=" s = "\(expr.0) \(cmp) \(expr.1)" } print("\(1,2)" as DiffString) //=> 1 != 2 print("\(5,5)" as DiffString) //=> 5 == 5
他にも便利そうな応用例がありましたら教えてください。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。