Replace repeating Character and UnicodeScalar forms of String.init
01 何が問題だったのか
Swift 3.0 より前の String には、同じ値を count 回繰り返して文字列を作るイニシャライザが Character 版と UnicodeScalar 版の2種類用意されていました。
public init(repeating repeatedValue: Character, count: Int)
public init(repeating repeatedValue: UnicodeScalar, count: Int)
一見すると便利ですが、"0" のような文字列リテラルはどちらの型としても解釈できるため、次のコードはあいまいとしてコンパイルエラーになります。
let x = String(repeating: "0", count: 10)
// error: ambiguous use of 'init(repeating:count:)'
エラーを避けるには、呼び出し側で型を明示するキャストが必要でした。
let zeroes = String(repeating: "0" as Character, count: 10)
// or
let zeroes = String(repeating: "0" as UnicodeScalar, count: 10)
「"0" を10個つなげた文字列が欲しい」というよくある用途に対して、型名を書き添えなければならないのは過剰な負担です。加えて、Character と UnicodeScalar のどちらを選ぶかで挙動が変わるわけでもなく、ユーザーから見れば区別にほとんど意味がありません。
同じ不整合は String.append 側にも存在し、UnicodeScalar を引数に取るオーバーロードが String を取るオーバーロードと並存していました。
public mutating func append(_ x: UnicodeScalar)
public mutating func append(_ other: String)
こちらは UnicodeScalar 版がなくても String 版で完全に代替できるため、わざわざ別オーバーロードを用意する理由が乏しい状態でした。
02 どのように解決されるのか
繰り返し用のイニシャライザを String を受け取る単一のAPIに統合し、あいまい性の原因そのものを取り除きます。
新しいイニシャライザ
Character 版と UnicodeScalar 版の2つに代わり、次の1つだけが提供されます。
public init(repeating repeatedValue: String, count: Int)
繰り返す値が String になったため、これまで曖昧だった呼び出しもキャストなしでそのまま書けます。
let zeroes = String(repeating: "0", count: 10)
// "0000000000"
単一の文字だけでなく、任意の文字列を繰り返せるようになったのも実用上の利点です。
let separator = String(repeating: "-=", count: 5)
// "-=-=-=-=-="
append の整理
String.append からも UnicodeScalar を取るオーバーロードが削除され、String を取る次の1つに集約されます。
public mutating func append(_ other: String)
UnicodeScalar を直接追加していたコードは、String に変換して渡すか、String リテラルとして書き直せば同じ結果が得られます。
var s = "abc"
let scalar: UnicodeScalar = "!"
s.append(String(scalar))
// s == "abc!"
既存コードへの影響
削除されるAPIを使っていたコードは書き換えが必要です。典型的には次のような対応になります。
String(repeating: x as Character, count: n)/String(repeating: x as UnicodeScalar, count: n)→String(repeating: String(x), count: n)、または繰り返したい値を直接Stringリテラルとして渡す形に変更s.append(scalar)(scalarがUnicodeScalar)→s.append(String(scalar))
いずれも機械的に置換可能で、fix-itによる自動マイグレーションも想定されています。