Swift 在结构中内存/缓存惰性变量

标签 swift memoization swift-structs

我喝了 Swift 中的 struct/value koolaid。现在我有一个有趣的问题,我不知道如何解决。我有一个容器结构,例如

struct Foo {
    var bars:[Bar]
}

当我对此进行编辑时,我会创建副本以便保留撤消堆栈。到目前为止,一切都很好。就像好的教程所显示的那样。不过,我对这个人使用了一些派生属性:

struct Foo {
    var bars:[Bar]

    var derivedValue:Int {
        ...
    }
}

在最近的分析中,我注意到 a) 计算 derivedValue 的计算有点昂贵/冗余 b) 在各种用例中并不总是需要计算。

以我经典的 OOP 方式,我会将其设为内存/惰性变量。基本上,在调用之前让它为零,计算一次并存储它,并在以后的调用中返回所述结果。由于我遵循“制作副本以进行编辑”模式,因此不会破坏不变量。

但是如果它是结构的,我不知道如何应用这个模式。我可以这样做:

struct Foo {
    var bars:[Bar]
    lazy var derivedValue:Int = self.computeDerivation()
}

这有效,直到结构引用该值本身,例如

struct Foo {
    var bars:[Bar]
    lazy var derivedValue:Int = self.computeDerivation()

    fun anotherDerivedComputation() {
        return self.derivedValue / 2
    }
}

此时,编译器会报错,因为 anotherDerivedComputation 导致接收器发生变化,因此需要标记为 mutating。将访问器标记为变异只是感觉不对。但是对于笑容,我尝试了一下,但这会产生一系列新的问题。现在任何地方我都有这样的表达

XCTAssertEqaul(foo.anotherDerivedComputation(), 20)

编译器会报错,因为参数是隐式的非可变 let 值,而不是 var。

我是否缺少一种模式,因为它具有一个具有延迟/惰性/缓存成员的结构?

最佳答案

内存不会发生在结构内部。 memoize 的方法是将字典存储在一些单独的空间。关键是推导值的任何内容,而值是计算一次的值。您可以将其设为结构类型的静态,就像命名空间的一种方式一样。

struct S {
    static var memo = [Int:Int]()
    var i : Int
    var square : Int {
        if let result = S.memo[i] {return result}
        print("calculating")
        let newresult = i*i // pretend that's expensive
        S.memo[i] = newresult
        return newresult
    }
}

var s = S(i:2)
s.square // calculating
s = S(i:2)
s.square // [nothing]
s = S(i:3)
s.square // calculating

关于Swift 在结构中内存/缓存惰性变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51730468/

相关文章:

ios - 将 Swift 的 Vision 库识别的文本分配给结构体的实例属性以进行显示时出现问题

swift - 按下按钮时的当前位置 map 图钉

ios - UICollectionViewCompositionalLayout 最小项目大小

swift - 删除单元格后 collectionViewCell 中的按钮索引错误

ios - SKShapeNode 尺寸错误

浏览器中的 Javascript Memoization 没有看到加速

python - 如何创建一个与索引无关的二元组?

ruby - 在 Ruby 中内存具有多个参数的函数

swift - 从镜像反省如何改变 child 的值(value)观

swift - swift 中的变异结构函数是否会创建一个新的 self 副本?