懒让?结构中的快速解决方法

Lazy let? Unswifty workaround in structs

我有一个正在使用的不可变结构,我正在尝试创建一个 属性,它 不是 计算值,但它是赋值需要先前分配的属性的值。

(哇一口)

我正在努力的 属性 是 perimeter: Int

// Floor made out of square tiles.
struct Floor { 

  let
  size:           (x: Int, y: Int), // How many tiles in the floor
  tilePerimeter:  Int,

  // Calculate entire floor's perimeter based on tile quantity and perimeter:
  lazy let perimeter: Int = {

    let
    t4th  = self.tilePerimeter / 4,  // Tile width / length
    sx    = self.size.x * t4th,      // All X tiles' length
    sy    = self.size.y * t4th       // All Y tiles' width

    return (sx * 2) + (sy * 2)       // Perimeter calc
  }()
};

不幸的是,Swift 不允许我使用 lazy let.. 所以我的解决方法是只使用 getter.. 计算 var。 .但是如果这个计算花费了很长时间(加载图像或复杂的数学)那么它会被调用很多次,而实际上它只需要调用一次一次

所以我的实际解决方法是创建一个初始化程序并在那里分配周长...只有我的一些结构具有许多属性,而不为结构创建初始化程序是 Swiftiness 的一部分我爱的。

我知道我可以将其设为 lazy var 并将结构实例化为 let,但这似乎令人困惑且容易出错。

有没有一种方法可以保持不变性、性能和 Swiftiness?还有,为什么不允许使用lazy let

您可以通过使用默认值为 nil 的可选私有变量来强制仅计算一次,同时仍然使用只读计算变量,这与实现单例对象的方式非常相似。

// Floor made out of square tiles.
struct Floor {
  private var computedPerimeter: Int? = nil

  let
  size:           (x: Int, y: Int), // How many tiles in the floor
  tilePerimeter:  Int

  // Calculate entire floor's perimeter based on tile quantity and perimeter:
  var perimeter: Int {
    mutating get {
        if computedPerimeter == nil {
            let
            t4th  = self.tilePerimeter / 4,  // Tile width / length
            sx    = self.size.x * t4th,      // All X tiles' length
            sy    = self.size.y * t4th       // All Y tiles' width

            computedPerimeter = ((sx * 2) + (sy * 2))       // Perimeter calc
         }
         return computedPerimeter!
     }
  }
};

也许你毕竟可以使用 lazy var:

lazy private(set) var perimeter: Int = {
    ...
}()

A​​ 只读 var 让您更接近所需的 let 语义。

使用初始化方法:

struct Floor {

    let size: (x: Int, y: Int), // How many tiles in the floor
    tilePerimeter: Int,
    perimeter: Int
  
    init(size:(x: Int, y: Int), tilePerimeter:  Int){
        self.size = size
        self.tilePerimeter = tilePerimeter
        
        // Calculate entire floor's perimeter based on tile quantity and perimeter:
        let
        t4th  = tilePerimeter / 4,  // Tile width / length
        sx    = size.x * t4th,      // All X tiles' length
        sy    = size.y * t4th       // All Y tiles' width

        self.perimeter = (sx * 2) + (sy * 2)       // Perimeter calc
    }
}