我的目标是能够将新项目插入到该集合之前具有零值的可选集合中。出于这个原因,我创建了这个扩展,但它不起作用,而且我仍然无法将新项目插入到零集中。
extension Optional where Wrapped == Set<String> {
func myInsert(_ value: String) -> Self {
if let unwrappedSet: Set<String> = self {
var newSet: Set<String> = unwrappedSet
newSet.insert(value)
return newSet
}
else {
let set: Set<String>? = [value]
return set
}
}
}
用例:
func myTest() -> Set<String>? {
var set: Set<String>? = nil
set.myInsert("Hello")
return set
}
if let set: Set<String> = myTest() {
print(set)
}
我拒绝相信我的扩展有问题,我认为问题来自 xcode 本身,看看它下面的函数是相同的函数,但在扩展之外,它确实有效!
func myInsert(set: Set<String>?, value: String) -> Set<String>? {
if let unwrappedSet: Set<String> = set {
var newSet: Set<String> = unwrappedSet
newSet.insert(value)
return newSet
}
else {
let set: Set<String>? = [value]
return set
}
}
用例:
let set: Set<String>? = nil
let newSet = myInsert(set: set, value: "Hello")
let newSet2 = myInsert(set: newSet, value: "World")
print(newSet2)
结果:
可选(设置(["你好", "世界"]))
从测试用例代码:
var set: Set<String>? = nil
set.myInsert("Hello")
您希望变量set
从nil
更改为包含String
"Hello"
的包装Set<String>
。 为了使值自行修改,必须mutating
func
。
将myInsert
设为mutating
func
并将新set
分配给self
。 由于myInsert
是mutating
,因此它不需要返回您的测试忽略的值:
extension Optional where Wrapped == Set<String> {
mutating func myInsert(_ value: String) {
if self == nil {
self = [value]
} else {
self?.insert(value)
}
}
}
<小时 />测试
func myTest() -> Set<String>? {
var set: Set<String>? = nil
set.myInsert("Hello")
set.myInsert("Goodbye")
return set
}
if let set = myTest() {
print(set)
}
<小时 />["Hello", "Goodbye"]
使insert
更易于使用
(感谢@LeoDabus的建议)
我们可以使用任何类型的Set
来使其工作,并通过让它返回一个包含元组的@discardableResult
,并带有一个指示值是否已插入的Bool
和memberAfterInsert
,使其更像Set
上的原始insert
:
extension Optional where Wrapped: SetAlgebra {
@discardableResult
mutating func insert(_ newMember: Wrapped.Element) -> (inserted: Bool, memberAfterInsert: Wrapped.Element) {
if self == nil {
self = .init()
}
return self!.insert(newMember)
}
}
vacawama 和 Leo 的答案是正确的,但你想了解为什么你的代码不起作用。我将尝试解释为什么无法按预期工作。您创建的函数"myInsert"定义了一个 Set 对象,插入参数值并返回新创建的 Set 对象。问题是您实际上并没有将创建的 Set 对象分配给您正在处理的实际 Set 变量(即"self")。
if let unwrappedSet: Set<String> = self {
var newSet: Set<String> = unwrappedSet // assigning nil valued "self" to a variable doesn't assign the original variable. Assigning nil to another variable makes that variable again nil. Both are equal (they are nil) but not same variables.
newSet.insert(value) // inserts value to second Set object not to "self". So still, your actual Set doesn't contains the given value.
return newSet // returns the value inserted Set object, not "self".
}
else {
let set: Set<String>? = [value]
return set
}
如果我们查看 myTest() 函数,您可以看到您的添加操作不适用于实际变量。
var set: Set<String>? = nil
set.myInsert("Hello") // at this point, myInsert function returns a new Set object with inserted given value. But this operation does not effect the original variable above. That means set variable is still nil
return set // returns nil variable.
我希望这有所帮助。