Swiftでテストデータなどを作成する時に、Arrayに同じ値を複数個入れて初期化したい時があります。
そういう時に、つい、こういうやり方をしてしまいがちです。
// 直書きで入れる
var array = [0,0,0,0,0]
// クロージャーでfor文を使う
var array: [Int] = {
var array = [Int]()
for _ in 0 ..< 5 {
array.append(0)
}
return array
}()
もっと便利に書く方法
SwiftのArrayには、以下のようなイニシャライズがあります。
public init(repeating repeatedValue: Array.Element, count: Int)
これは、repeatedValueに渡された値を、countの数だけ格納して初期化してくれるので、最初にあげたようなやり方を、スマートに書くことができます。
var array = [Int](repeating: 0, count: 5)
注意点
classオブジェクトをrepeatedValueに指定した場合、参照を複製してしまうため、Arrayの中身の値を書き換えた時に、初期化時の値全てに反映されてしまうので注意が必要です。
class TestClass {
var value = 0
}
var array = [TestClass](repeating: TestClass(), count: 5)
// 0番目を書き換えてログに出力する。
array[0].value = 100
array.forEach { print($0.value) }
// 0番目以外も変わってしまう!
/*
出力結果
100
100
100
100
100
*/
もちろんstructなどの値渡しオブジェクトを使用する際は、この注意点を気にする必要はありません。
struct TestStruct {
var value = 0
}
var array = [TestStruct](repeating: TestStruct(), count: 5)
array[0].value = 100
array.forEach { print($0.value) }
// 0番目だけが変わる!
/*
出力結果
100
0
0
0
0
*/
おまけ
Extension
どうしてもクラスでやりたいけれど、参照が複製されたら困る場合に使うArrayのExtensionです。
extension Array {
init(count: Int, repeating closure: () -> Element) {
var array = [Element]()
for _ in 0 ..< count {
array.append(closure())
}
self = array
}
}
使い方
var array = [TestClass](count: 5) { TestClass() }
array[0].value = 100
array.forEach { print($0.value) }
// 0番目だけが変わる!
/*
出力結果
100
0
0
0
0
*/