- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我是 Swift 的新手,决定编写自己的 Optional 枚举。
enum MyOptional<Type> {
case none
case some(Type)
func get() -> Type {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
}
var test: MyOptional<String> = MyOptional.some("testString")
test.get().append("#")
但如果我放置一些具有变异函数的结构并调用该函数 - 显然,编译器会告诉我:
error: cannot use mutating member on immutable value: function call returns immutable value test.get().append("#")
Swift 的 Optional 如何通过引用解包返回结构体?
最佳答案
Swift 编译器对Optional
有相当多的内置支持;包括后缀运算符 !
和 ?
,它们可以产生左值(驻留在内存中已知位置的值;因此如果表达式是可变的,则允许该内存发生突变).
不幸的是,我不认为可以实现您自己的左值返回运算符(或一般函数),尽管允许您定义 getter 和 setter(例如计算属性和下标)的构造可以被视为 l - 当他们有 setter 时的值:
enum MyOptional<Type> {
case none, some(Type)
var forceUnwrapped: Type {
get {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
set {
self = .some(newValue)
}
}
// just for demonstration; don't actually implement this as a subscript!
subscript() -> Type {
get {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
set {
self = .some(newValue)
}
}
}
var test = MyOptional.some("testString")
test.forceUnwrapped.append("#")
test[].append("#")
在这里,test.forceUnwrapped
和 test[]
可以被视为左值。当通过它们进行变异时,编译器将通过调用 getter 创建一个临时变量,对该临时变量进行变异,然后使用变异值调用 setter。
尽管在这两种情况下都值得注意,当与赋值一起使用时
(即 test.forceUnwrapped = ...
& test[] = ...
), getter 不会被调用;只有 setter,它赋予它们与 Optional
的后缀 !
略有不同的语义,即使在赋值时,它也会在可选为 nil
时崩溃(即 someOptional! = ...
).
作为替代方案,您还可以定义一个方法,该方法采用带有 inout
参数的闭包,允许调用者改变强制展开的值:
enum MyOptional<Type> {
case none
case some(Type)
mutating func forceMutate<R>(_ body: (inout Type) throws -> R) rethrows -> R {
switch self {
case .some(var x):
defer {
self = .some(x)
}
return try body(&x)
case .none:
fatalError()
}
}
}
var test = MyOptional.some("testString")
test.forceMutate { $0.append("#") }
关于Swift 枚举通过引用展开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47577004/
我是一名优秀的程序员,十分优秀!