swift5で次のコードを実行すると
Cannot use mutating member on immutable value: 'hoge' is a 'let' constant
と言うエラーが出ます。これにしばらくハマってしまったので解決方法を書いておきます。
protocol Hoge{
var items:[String]{get set}
}
class Fuga:Hoge{
var items: [String]
init(_ items: [String]){
self.items = items
}
}
class Piyo:Hoge{
var items: [String]
init(_ items: [String]){
self.items = items
}
}
var hoges:[Hoge] = [Fuga(["a"]), Piyo(["a"]), Fuga(["a"])]
hoges.forEach{ (hoge: Hoge) in
hoge.items.append("b") //エラー:Cannot use mutating member on immutable value: 'hoge' is a 'let' constant
}
print(hoges.map{$0.items})
items
は{get set}
で宣言しており、問題はないように見えますが、エラーではhoge
が定数だと言っています。forEach
内で変更しているのが問題なわけでもなく、実際次のコードはすんなり動きます。
var hoges:[Fuga] = [Fuga(["a"]), Fuga(["a"]), Fuga(["a"])]
hoges.forEach{ (hoge: Fuga) in
hoge.items.append("b")
}
このエラーの原因はprotocol
に準拠した型がclass
かstruct
か分からないことです。struct
は基本的に不変なので、もしもHoge
に準拠した型がstruct
だった場合変更ができなくなってしまいます。
ということで、対応にはprotocol
にclass
の制約をかけてあげることです。
protocol Hoge:class{ //ここが大事!!!!
var items:[String]{get set}
}
class Fuga:Hoge{
var items: [String]
init(_ items: [String]){
self.items = items
}
}
class Piyo:Hoge{
var items: [String]
init(_ items: [String]){
self.items = items
}
}
var hoges:[Hoge] = [Fuga(["a"]), Piyo(["a"]), Fuga(["a"])]
hoges.forEach{ (hoge: Hoge) in
hoge.items.append("b")
}
print(hoges.map{$0.items})
以上です。