我创建了一个新运算符,该运算符仅在值不为 nil 时才将值关联到目标,否则什么也不做。基本上它是if let foo = foo { faa = foo }
的合成糖:
infix operator =? {}
func =?<T>(inout lhs: T, rhs: T?) {
if let rhs = rhs {
lhs = rhs
}
}
func =?<T>(inout lhs: T?, rhs: T?) {
if let rhs = rhs {
lhs = rhs
}
}
这样我就可以节省一些输入:
// instead this:
if let x = maybeX {
z = x
}
// I can do this:
z =? x
我的问题是,当我到达执行行(z =? x
)时,我甚至在进入实现功能之前就崩溃了,但有例外:
fatal error: unexpectedly found nil while unwrapping an Optional value
看起来 Swift 试图强制解包x
即使实现接受T?
。
有什么想法吗?
似乎是我的错误...我正在使用foo.z = ...
,foo
是一个零UIImageView!
......从笔尖看大坝的景色...
我很乐意按照@RMenke的建议使用 nil 合并运算符更改我的实现,但据我所知,这将导致在 x 为 nil 时将 z 设置为 z 的冗余操作......例如:
var z = someFoo()
var x: Int? = nil
z = x ?? z
// will this re-write z's reference to z again or simply do nothing?
@MartinR发表了一个重要的评论:
如果运算符(或函数)采用 inout-参数,则即使您没有在运算符中分配新值,也会在返回时调用属性 setter
为了解决这个问题,我做了以下扩展,作为_ = foo.map...
方法的更干净版本:
extension Optional {
public func use<U>(@noescape f: (Wrapped) throws -> U) rethrows {
_ = try self.map(f)
}
}
//then:
x.use{ z = $0 }
它可能更好,因为它在 x 为 nil 时不调用 z 的 setter,但它是最干净/最清晰的方法吗?
您的运算符有效,但您应该使用链接的可选:foo?。z = ...
但是,当foo为nil时,这将为您提供另一种错误,您可以通过添加
func =?<T>(lhs: T??, rhs: T?) -> ()
{}
这个"无所事事"版本的运算符吸收了您在传递在最后一个成员之前具有 nil 的可选链时获得的不可变参数版本。