在 Swift 中,我有一个自定义的 Deque 结构,其中包含用于添加和删除元素的各种变异方法。当我链接 Deque.pushBack(contentsOf: ...) 等方法调用时,遇到错误“无法在不可变值上使用变异成员:函数调用返回不可变值”。然而,当我在像 b 这样的变量上使用相同的链接模式时,它工作得很好。有人可以解释为什么会发生这种情况吗?这与 match 函数是全局函数有关吗?我该如何解决这个问题?
struct Deque {
private var arrayDeque: [Int] = []
mutating func pushFront(_ element: Int) {
arrayDeque.insert(element, at: 0)
}
@discardableResult
mutating func pushFront(contentsOf elements: Int...) -> Deque {
for element in elements.reversed() {
pushFront(element)
}
return self
}
mutating func pushBack(_ element: Int) {
arrayDeque.append(element)
}
@discardableResult
mutating func pushBack(contentsOf elements: Int...) -> Deque {
for element in elements {
pushBack(element)
}
return self
}
@discardableResult
mutating func popFront() -> Deque? {
guard !isEmpty else { return nil }
var copy = self
copy.arrayDeque.removeFirst()
return copy
}
@discardableResult
mutating func popBack() -> Deque? {
guard !isEmpty else { return nil }
var copy = self
copy.arrayDeque.removeLast()
return copy
}
var isEmpty: Bool {
return arrayDeque.isEmpty
}
var count: Int {
return arrayDeque.count
}
func peekFront() -> Int? {
return arrayDeque.first
}
func peekBack() -> Int? {
return arrayDeque.last
}
}
func match(_ xs: Deque) -> Bool { ... }
// gives me error
let a = match(Deque().pushBack(contentsOf: 1, 2, 1, 2, 1))
// works fine
var b = Deque()
let b2 = b.pushBack(contentsOf: 1, 2, 1, 2, 1)
let b3 = match(b2)
错误:无法在不可变值上使用变异成员:函数调用返回不可变值
我试图理解为什么 Swift 在这些场景中表现不同,以及如何在链接方法调用自定义数据结构时确保行为一致。任何见解或解释将不胜感激! (我是新手,如果你能用基本术语解释那就太好了,谢谢)
还有 chatGPT 解释:“实例的可变性:如果您在实例上链接可变方法,请确保实例本身是可变的(用 var 声明)。否则,您将无法应用实例所做的更改方法。”,以及关于如何“是因为在 Swift 中,当你像示例 a 那样链接方法调用时,中间结果是不可变的。”
没有任何“技术”原因不允许您这样做,但在大多数情况下。对返回值调用变异函数很可能是一个错误。 (另请参阅)考虑一个相当人为的示例:
var deque = Deque()
func returnADeque() -> Deque { return deque }
// suppose this is allowed
returnADeque().pushBack(1)
这实际上不会修改全局变量
deque
。
Deque
是一个结构体(值类型),因此 returnADeque
返回它的副本。这同样适用于初始化器。从调用者的角度来看,初始化器只是一个函数,它返回它正在初始化的任何类型的实例。假设 pushBack
没有
return self
,那么 Deque().pushBack(contentsOf: 1, 2, 1, 2, 1)
不会做任何有用的工作。您创建一个 Deque
,然后将一些数字推入其中,然后丢弃它,而不使用您推入的任何内容。要执行此链接,您可以将 Deque
更改为具有不同语义的类(引用类型)。您还可以为每个函数制作两个版本 - 一种不是
mutating
并返回 self
用于链接,另一种是 mutating
并且不返回 self
。 mutating func pushBack(contentsOf elements: Int...) {
for element in elements {
pushBack(element)
}
}
func pushedBack(contentsOf elements: Int...) -> Deque {
var copy = self
// normally you can reuse the mutating function here, but because pushBack
// takes a variadic Int..., it is not possible in this case
for element in elements {
copy.pushBack(element)
}
return copy
}
允许链接的方法应使用动词的过去分词,以遵循标准库中使用的命名约定
。 shuffle()
与
shuffled()
、reverse()
与 reversed()
等