gpt4 book ai didi

swift - 如何正确地在 Swift 中的变异结构上创建惰性派生属性?

转载 作者:搜寻专家 更新时间:2023-10-30 22:10:44 25 4
gpt4 key购买 nike

我正在制作一个变异结构,其派生值的计算成本非常高。所以我想做的是懒惰地计算这个派生值并存储结果,直到结构再次发生变异,此时派生值不再有效,需要重新计算。

(失败)选项 1:生成的属性

如果派生值是生成的属性(如下所示),则始终返回正确的值,但始终会重新计算。

(失败)选项 2:延迟加载属性

如果它是惰性属性,则计算只进行一次……永远。因此,一旦结构发生变异,派生值就会错误,并且不会重新计算。此外,如果我从结构中分配常量值,我将无法访问该属性。

在 Swift 1.2 中是否有任何可能的解决方案,或者我是否需要提交雷达?

struct Struct {
var value: Int

// Option 1: Generated property
var derivedValue: Int {
println("Doing expensive calculation")
return self.value * 2
}

// Option 2: Lazy property
lazy var derivedValue: Int = {
println("Doing expensive calculation")
return self.value * 2
}()

init(value: Int) {
self.value = value
}

mutating func mutate() {
value = random()
}
}

var test = Struct(value: 2)
test.derivedValue
test.derivedValue // If not lazy, expensive calculation is done again here
test.mutate()
test.derivedValue // If lazy, this has wrong value

let test2 = test
test2.derivedValue // Compiler error if using lazy implementation

最佳答案

使用嵌入式类绕过了改变结构的限制。这使您可以使用按值类型,该类型在需要时才运行昂贵的计算,但之后仍会记住结果。

下面的示例 Number 结构以您描述的方式计算并记住其 square 属性。数学本身效率低得离谱,但它是说明解决方案的简单方法。

struct Number {

// Store a cache in a nested class.
// The struct only contains a reference to the class, not the class itself,
// so the struct cannot prevent the class from mutating.
private class Cache {
var square: Int?
var multiples: [Int: Int] = [:]
}
private var cache = Cache()

// Empty the cache whenever the struct mutates.
var value: Int {
willSet {
cache = Cache()
}
}

// Prevent Swift from generating an unwanted default initializer.
// (i.e. init(cache: Number.Cache, value: Int))
init(value: Int) {
self.value = value
}

var square: Int {
// If the computed variable has been cached...
if let result = cache.square {

// ...return it.
print("I’m glad I don’t have to do that again.")
return result
} else {

// Otherwise perform the expensive calculation...
print("This is taking forever!")
var result = 0
for var i = 1; i <= value; ++i {
result += value
}

// ...store the result to the cache...
cache.square = result

// ...and return it.
return result
}
}

// A more complex example that caches the varying results
// of performing an expensive operation on an input parameter.
func multiple(coefficient: Int) -> Int {
if let result = cache.multiples[coefficient] {
return result
} else {

var result = 0
for var i = 1; i <= coefficient; ++i {
result += value
}

cache.multiples[coefficient] = result
return result
}
}
}

这是它的表现:

// The expensive calculation only happens once...
var number = Number(value: 1000)
let a = number.square // “This is taking forever!”
let b = number.square // “I’m glad I don’t have to do that again.”
let c = number.square // “I’m glad I don’t have to do that again.”

// Unless there has been a mutation since last time.
number.value = 10000
let d = number.square // “This is taking forever!”
let e = number.square // “I’m glad I don’t have to do that again.”

// The cache even persists across copies...
var anotherNumber = number
let f = anotherNumber.square // “I’m glad I don’t have to do that again.”

// ... until they mutate.
anotherNumber.value = 100
let g = anotherNumber.square // “This is taking forever!”

作为一个更现实的例子,我在日期结构上使用了这种技术,以确保尽可能少地运行用于在日历系统之间转换的重要计算。

关于swift - 如何正确地在 Swift 中的变异结构上创建惰性派生属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28901871/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com