【问题标题】:Is it possible to point class instance variables to `inout` parameters in Swift?是否可以将类实例变量指向 Swift 中的“inout”参数?
【发布时间】:2022-01-03 21:14:47
【问题描述】:

多个类方法是否可以访问和修改在类构造函数中设置的单个 inout 参数?例如这样的:

class X {
    var mySwitch: Bool
    
    init(mySwitch: inout Bool) {
        self.mySwitch = mySwitch
    }
    
    func updateSwitch() {
        self.mySwitch.toggle() // this should toggle the external Boolean value that was originally passed into the init
  }
}

// usage
var myBool: Bool = false
let x = X(mySwitch: &myBool)
x.updateSwitch()
print(myBool) // this should read 'true'

【问题讨论】:

  • 明确禁止将捕获更改为像这样的值类型,特别是为了防止这种情况。允许这样做会使它们进入共享可变状态,这完全违背了值类型的目的。
  • 你能扩展explicitly forbidden, specifically to prevent this吗?即使值类型可以具有共享状态(通过使用 & 将它们显式传递给 inout 参数),将其限制在单个方法的范围内是否有一些优势?
  • inout 就像在将值传递给调用时复制了该值,并在调用结束时复制了(覆盖原始值)。不会发生别名(对同一可变状态的多次引用),因此是可以接受的。
  • 知道了,谢谢@Alexander。

标签: swift sprite-kit


【解决方案1】:

简答

没有。

长答案

还有其他方法可以满足这一点。

绑定变量

在 SwiftUI 中,我们使用绑定变量来做这样的事情。当 Binding 变量更新时,它也会更新绑定变量。我不确定它是否可以在 Sprite Kit 中使用。

class X {
    var mySwitch: Binding<Bool>

    init(_ someSwitch: Binding<Bool>) {
        self.mySwitch = someSwitch 
    }

   func toggle() { mySwitch.wrappedValue.toggle() }
}

struct Y {
    @State var mySwitch: Bool = false
    lazy var switchHandler = X($mySwitch)
} 

回调

我们可以向X 添加一个回调,并在布尔值的didSet 上调用它。

class X {
    var mySwitch: Bool {
        didSet { self.callback(mySwitch) } // hands the new value back to the call site in Y
    }

    let callback: (Bool) -> Void

    init(_ someSwitch: Bool, _ callback: @escaping (Bool) -> Void) {
        self.mySwitch = someSwitch
        self.callback = callback
    }

    func toggle() { mySwitch = !mySwitch } // explicitly set to trigger didSet
}

class Y {
    var mySwitch: Bool = false
    lazy var switchHandler = X(mySwitch) {
        self.mySwitch = $0 // this is where we update the local value
    }
}

【讨论】:

  • 感谢您的详尽回答。我总是可以将 SwiftUI 导入到我的 SpriteKit 文件中以利用 Binding,但我将使用回调模式,因为它看起来非常简单,并为轻松实现附加功能打开了大门。
【解决方案2】:

您不能以这种方式“链接”变量,因为inout 仅在它声明的范围内有效。

如果你想要某种全局状态,你可以将它包装在一个类中。

class Wrapper {
    var value = false
    init() {}
}

class Modifier {
    let wrapper: Wrapper
    init(wrapper: Wrapper) {
        self.wrapper = wrapper
    }
    
    func updateSwitch() {
        wrapper.value.toggle()
    }
}

let wrapper = Wrapper()
let modifier = Modifier(wrapper: wrapper)
modifier.updateSwitch()
print(wrapper.value) // this will read 'true'

【讨论】:

    【解决方案3】:

    简短回答:否。

    你的问题没有意义。 inout 参数允许您在调用函数期间对参数进行读/写访问。一旦函数返回,它就没有意义了。您似乎认为它在作为 inout 传递的参数和其他一些变量之间创建了一些持久的链接。它没有。

    【讨论】:

    • 我并不是在暗示 inout 参数会创建“一些持久链接”,而是我想知道是否有一种在 Swift 中利用指针的好方法/为什么 inout 必须这样做仅限于调用函数。上面提到的模式在任何情况下都非常有用。
    • 查看 Jakes 的回答,他在其中引用了 SwiftUI 中的绑定变量。这种方法听起来像你的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 2015-10-07
    • 2020-11-14
    • 2016-05-21
    相关资源
    最近更新 更多