如何在Swift中的变异结构上正确创建一个延迟派生属性?

前端之家收集整理的这篇文章主要介绍了如何在Swift中的变异结构上正确创建一个延迟派生属性?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在制作一个具有非常昂贵的计算导出值的变异结构.所以我想做的是懒惰地计算这个派生值并存储结果,直到结构再次发生变异,此时派生值不再有效,需要重新计算.

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

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

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

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

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

  1. struct Struct {
  2. var value: Int
  3.  
  4. // Option 1: Generated property
  5. var derivedValue: Int {
  6. println("Doing expensive calculation")
  7. return self.value * 2
  8. }
  9.  
  10. // Option 2: Lazy property
  11. lazy var derivedValue: Int = {
  12. println("Doing expensive calculation")
  13. return self.value * 2
  14. }()
  15.  
  16. init(value: Int) {
  17. self.value = value
  18. }
  19.  
  20. mutating func mutate() {
  21. value = random()
  22. }
  23. }
  24.  
  25. var test = Struct(value: 2)
  26. test.derivedValue
  27. test.derivedValue // If not lazy,expensive calculation is done again here
  28. test.mutate()
  29. test.derivedValue // If lazy,this has wrong value
  30.  
  31. let test2 = test
  32. test2.derivedValue // Compiler error if using lazy implementation
使用嵌入式类可以解决变异结构的限制.这允许您使用按值类型,该类型在需要之前不会运行昂贵的计算,但仍会记住之后的结果.

下面的示例数字结构以一种与您描述的方式相似的方式计算并记住其方形属性.数学本身效率低得离谱,但这是解释解决方案的简单方法.

  1. struct Number {
  2.  
  3. // Store a cache in a nested class.
  4. // The struct only contains a reference to the class,not the class itself,// so the struct cannot prevent the class from mutating.
  5. private class Cache {
  6. var square: Int?
  7. var multiples: [Int: Int] = [:]
  8. }
  9. private var cache = Cache()
  10.  
  11. // Empty the cache whenever the struct mutates.
  12. var value: Int {
  13. willSet {
  14. cache = Cache()
  15. }
  16. }
  17.  
  18. // Prevent Swift from generating an unwanted default initializer.
  19. // (i.e. init(cache: Number.Cache,value: Int))
  20. init(value: Int) {
  21. self.value = value
  22. }
  23.  
  24. var square: Int {
  25. // If the computed variable has been cached...
  26. if let result = cache.square {
  27.  
  28. // ...return it.
  29. print("I’m glad I don’t have to do that again.")
  30. return result
  31. } else {
  32.  
  33. // Otherwise perform the expensive calculation...
  34. print("This is taking forever!")
  35. var result = 0
  36. for var i = 1; i <= value; ++i {
  37. result += value
  38. }
  39.  
  40. // ...store the result to the cache...
  41. cache.square = result
  42.  
  43. // ...and return it.
  44. return result
  45. }
  46. }
  47.  
  48. // A more complex example that caches the varying results
  49. // of performing an expensive operation on an input parameter.
  50. func multiple(coefficient: Int) -> Int {
  51. if let result = cache.multiples[coefficient] {
  52. return result
  53. } else {
  54.  
  55. var result = 0
  56. for var i = 1; i <= coefficient; ++i {
  57. result += value
  58. }
  59.  
  60. cache.multiples[coefficient] = result
  61. return result
  62. }
  63. }
  64. }

这就是它的表现:

  1. // The expensive calculation only happens once...
  2. var number = Number(value: 1000)
  3. let a = number.square // “This is taking forever!”
  4. let b = number.square // “I’m glad I don’t have to do that again.”
  5. let c = number.square // “I’m glad I don’t have to do that again.”
  6.  
  7. // Unless there has been a mutation since last time.
  8. number.value = 10000
  9. let d = number.square // “This is taking forever!”
  10. let e = number.square // “I’m glad I don’t have to do that again.”
  11.  
  12. // The cache even persists across copies...
  13. var anotherNumber = number
  14. let f = anotherNumber.square // “I’m glad I don’t have to do that again.”
  15.  
  16. // ... until they mutate.
  17. anotherNumber.value = 100
  18. let g = anotherNumber.square // “This is taking forever!”

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

猜你在找的Swift相关文章