在Swift中,我有一个自定义的Deque struct ,其中包含各种用于添加和删除元素的变异方法.当我链接Deque.pushBack(contentsOf:.)等方法调用时,我遇到错误"无法在不可变值上使用变异成员:函数调用返回不可变值."然而,当我对b这样的变量使用相同的链接模式时,它工作得很好.有人能解释一下为什么会发生这种情况吗?与匹配函数是全局函数有关吗?如何解决这个问题?

 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在这些场景中的行为不同,以及如何在链接方法调用自定义数据 struct 时确保行为一致.任何见解或解释都将不胜感激!(我是新手,如果你能用基本术语解释一下那就太好了,谢谢)

还聊天GPT解释:"实例的可变性:如果您在实例上链接可变方法,请确保实例本身是可变的(用var声明).否则,您将无法应用方法所做的更改.",以及关于如何"的一些内容是因为在Swift中,当您像示例a中那样链接方法调用时,中间结果是不可变的."

推荐答案

没有technical个理由可以解释为什么不允许这样做,但在大多数情况下.对返回值调用变异函数很可能是一个错误.(See also)考虑一个相当做作的例子:

var deque = Deque()
func returnADeque() -> Deque { return deque }

// suppose this is allowed
returnADeque().pushBack(1)

这实际上不会修改全局变量deque.Deque是一个 struct (值类型),因此returnADeque返回它的副本.

这同样适用于初始化者.从调用者的Angular 来看,初始化器只是一个函数,它返回它正在初始化的任何类型的实例.假设pushBack不是return self,那么Deque().pushBack(contentsOf: 1, 2, 1, 2, 1)不会做任何有用的工作.您创建一个Deque,然后将一些数字推入其中,然后丢弃它,不使用您推入的任何内容.

要执行此链接,您可以将Deque更改为具有不同语义的类(引用类型).您还可以 for each 函数创建两个版本-一个不是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
}

允许链接的方法应该使用动词的过go 助词,遵循标准库中使用的naming conventions.shuffle() vs shuffled()reverse() vs reversed()

Swift相关问答推荐

Swift:iVar + Equatable上的协议约束

异步/等待函数的XCTAssertThrowsError

如何将新事例添加到枚举中?

如何在应用程序区域永久更改 NSCursor?

BLE 在 ESP32 和 Iphone 之间发送字符串

SwiftUI如何能够在Text中使用字符串字面量来创建LocalizedStringKey?

SwiftUI 交易:根据外部状态制作一个动画或静止的按钮

SwiftUI:列表背景为空列表时为黑色

如何在 switch case 模式语句中使用 Swift 文字正则表达式?

Swift-SceneKit-无法从art.scnassets加载.scn文件

Vapor 4 身份验证问题 [用户未通过身份验证]

SwiftUI:当先前的视图列表更改时,NavigationView 详细视图会弹出回栈

在 RealityKit 中创建转场

SwiftUI 中的计时器崩溃屏幕

如何在 Swift 中返回 Task 中定义的变量

在视图中设置所有变量

是否可以在 Swift 中创建通用闭包?

SwiftUI - 呈现工作表后导航栏按钮不可点击

不能从非开放类继承 swift

Swift中字节数组的NSData