書いたこと
- precedencegroup assignment 属性の役割について
- assignment属性が false の場合のカスタム代入演算子の動作について
- assignment属性が true の場合のカスタム代入演算子の動作について
assignment属性値の役割
カスタムの代入演算子を定義した際に、assignment属性値がtrueのprecedencegroupに属する場合、オプショナルチェーンを挟んだ代入が行えるようになります。
以下カスタムの ??= 代入演算子を使って、
assignementがfalseのprecedencegroupに属する場合とtrueのprecedencegroupに属する場合で上記の動作を確認します。
assignment属性値がfalseのprecedencegroupに属する場合
precedencegroup NoAssignmentPrecedence {
assignment: false
}
infix operator ??=: NoAssignmentPrecedence
以下のようにオプショナルチェーンを挟んだ代入ができなくなる。
class Foo {
var bar: Int? = nil
}
let foo: Foo? = Foo();
// error: cannot pass immutable value of type 'Int?' as inout argument
foo?.bar ??= 10
エラーを読むと上記は以下のように評価されているようです。
// foo?.bar ??= 10
if let foo = foo {
let bar = foo.bar
bar ??= 10
}
assignment属性値がtrueのprecedencegroupに属する場合
precedencegroup `AssignmentPrecedence` {
assignment: true
}
infix operator ??=: `AssignmentPrecedence`
以下のようにオプショナルチェーンを挟んだ代入が出来るようになります。
class Foo {
var bar: Int? = nil
}
let foo: Foo? = Foo();
// OK
foo?.bar ??= 10
上記は以下のように評価されるようです。
// foo?.bar ??= 10
if let foo = foo {
foo.bar ??= 10
}
??= 演算子
/// nilじゃない場合代入してくれる素敵なカスタム演算子です
func ??=<T>(lhs: inout T?, rhs: T) {
if lhs == nil { return }
lhs = rhs
}
以下のように使えます。
infix operator ??= : AssignmentPrecedence
class Foo {
var bar: Int? = nil
}
let foo = Foo(); foo.bar ??= 10 // foo.barに10が代入されます
参考サイト
- precedencegroupの定義
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID380 - the evolution proposal.
https://github.com/apple/swift-evolution/blob/master/proposals/0077-operator-precedence.md - ??=演算子について
http://stackoverflow.com/questions/39881308/null-coalescing-assignment-operator-in-swift-3