简体   繁体   English

在Swift中存储对struct的引用

[英]Store reference to struct in Swift

Let's say I have a model, called Car with a property color of type String : 假设我有一个名为Car的模型,其colorString类型:

class Car {
    var color: String?
}

Now, I have another class called Interface that I wish to use to modify the value of the color property of Car . 现在,我有另一个名为Interface类,希望用于修改Carcolor属性的值。 To do this, I'd like to somehow bind color to a property of Interface , such as key : 为此,我想以某种方式将color绑定到Interface的属性,例如key

class Interface {

    var storedKey: String?

    func bind(key: String?) {
        self.storedKey = key
    }
}

Usage: 用法:

let corolla = Car()
corolla.color = "green"
let interface = Interface()
interface.bind(key: &corolla.color)
interface.storedKey = "blue"
print(corolla.color) // still "green"! :(

This approach fails because strings are value types (structs) in Swift, so the bind function gets a copy of corolla.color , not a reference. 这种方法失败了,因为字符串是Swift中的值类型(结构),因此bind函数将获得corolla.color的副本,而不是引用。 This means modifying storedKey of interface has no effect on the value of corolla.color . 这意味着修改storedKeyinterface对的值没有影响corolla.color

If we add inout to the binding function as shown below, we basically obtain a reference to the key passed in ( it's actually copied in then copied out ), but it only lasts for the scope of the function. 如果我们按如下所示将inout添加到绑定函数中,则基本上可以得到对传入的键的引用( 它实际上是复制进来的,然后复制出来的 ),但是它仅在函数作用域内有效。

func bind(key: inout String?) {
    self.storedKey = key  // assignment of value type is a copy! :/
}

The results are the same, modifying storedKey has no effect on the property it is bound to. 结果是相同的,修改storedKey对其绑定的属性没有影响。

What this boils down to is, can we obtain a reference to a struct in Swift? 归结为是,我们可以在Swift中获得对结构的引用吗?


Since structs occupy space in memory, we may be able to obtain a pointer to the key passed in, here is a working (incorrect) solution: 由于结构占用了内存空间,因此我们可以获取指向传入键的指针,这是一个可行的(不正确)解决方案:

class Car {
    var color: String?
}

let corolla = Car()
corolla.color = "green"

class Interface {

    var storedKey: UnsafeMutablePointer<String?>?

    func bind(_ key: inout String?) {
        self.storedKey = withUnsafeMutablePointer(to: &key) { ptr in
            return ptr
        }
    }
}

var interface = Interface()
interface.bind(&corolla.color)
interface.storedKey?.pointee = "blue" // :O it's... working?
print(corolla.color)

As I see it, this breaks at least two semantic rules in Swift: 如我所见,这至少破坏了Swift中的两个语义规则:

  1. withUnsafeMutablePointer converts the address of an instance passed in via & to a UnsafeMutablePointer of that instances' type, to be used only within the provided closure. withUnsafeMutablePointer会将通过&传入的实例的地址转换为该实例类型的UnsafeMutablePointer仅在提供的闭包中使用。 As per the Swift docs : 根据Swift文档

    The pointer argument to body is valid only for the lifetime of the closure. 指向body的指针参数仅在关闭的有效期内有效。 Do not escape it from the closure for later use. 请勿将其从封盖中逸出以备后用。

  2. The second problem is that this takes advantage of a Swift compiler optimization that allows bind to actually obtain a reference to key instead of a copy. 第二个问题是,这利用了Swift编译器优化的优势,该优化允许bind实际获取对key的引用而不是副本。 Otherwise, the pointer would not obtain a reference to the original key, but to a copy. 否则,指针将不会获得对原始密钥的引用,而是对副本的引用。 inout parameters are normally implemented using a behavior known as copy-in copy-out, whereby a copy of the argument is passed in to the function, possibly modified, and then assigned back to the original argument. inout参数通常使用一种称为copy-in copy-out的行为来实现,从而将参数的副本传递到函数中,并可以对其进行修改,然后将其赋值回原始参数。 As per the docs , there is an optimization whereby if the argument is a stored property, the same memory location is used both inside and outside the function body. 根据docs ,有一个优化,如果参数是存储的属性,则在函数体内外都使用相同的内存位置。 This allowed our pointer to obtain a reference to the original String struct instead of a copy, allowing this to work. 这使我们的指针可以获得对原始String结构的引用,而不是对副本的引用,从而使其能够工作。

    As an optimization, when the argument is a value stored at a physical address in memory, the same memory location is used both inside and outside the function body. 作为优化,当参数是存储在内存中物理地址上的值时,在函数体内外都使用相同的存储位置。

Is there any way to store a reference to a struct such as String ? 有什么方法可以存储对诸如String的结构的引用? Or am I on a wild goose chase? 还是我在追逐野鹅?

Edit 1: Also, I have no control of the types of Car 's properties. 编辑1:另外,我无法控制Car的属性类型。

You can't get a reference to your struct as you already researched. 您已经研究过,因此无法获得对结构的引用。

What you can do is use a Box class and pass that around. 您可以做的是使用Box类并传递它。

Then you would use the Box everywhere and access its struct property wherever needed. 然后,您将在任何地方使用Box并在需要时访问其struct属性。

Something like: 就像是:

class Box<T> {
   var value: T
   init(value: T) {
      self.value = value
   }
}

and use it with a Car 并与汽车一起使用

let boxedCar = Box(value: Car(...)) 

You can share references to this box and always access the car through the value property 您可以共享对此框的引用,并始终通过value属性访问汽车

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM