Lazy Var vs Let

Yog*_*ton 46 var let lazy-initialization swift

我想对Swift中的一些属性使用Lazy初始化.我当前的代码如下所示:

lazy var fontSize : CGFloat = {
  if (someCase) {
    return CGFloat(30)
  } else {
    return CGFloat(17)
  }
}()
Run Code Online (Sandbox Code Playgroud)

问题是,一旦设置了fontSize,它将永远不会改变.所以我想做这样的事情:

lazy let fontSize : CGFloat = {
  if (someCase) {
    return CGFloat(30)
  } else {
    return CGFloat(17)
  }
}()
Run Code Online (Sandbox Code Playgroud)

这是不可能的.

只有这个有效:

let fontSize : CGFloat = {
  if (someCase) {
    return CGFloat(30)
  } else {
    return CGFloat(17)
  }
}()
Run Code Online (Sandbox Code Playgroud)

所以 - 我想要一个延迟加载但永远不会改变的属性.这样做的正确方法是什么?使用let和忘记懒惰的初始化?或者我应该使用lazy var并忘记属性的恒定性质?

Chr*_*ver 25

这是Xcode 6.3 Beta/Swift 1.2发行说明中的最新经文:

让常量已经推广到不再需要立即初始化.新规则是必须在使用前初始化let常量(如var),并且它只能初始化:初始化后不重新分配或变异.

这使得模式如下:

let x: SomeThing
if condition {
    x = foo()
} else {
    x = bar()
}

use(x)
Run Code Online (Sandbox Code Playgroud)

以前需要使用var,即使没有发生突变.(16181314)

显然你并不是唯一一个对此感到沮丧的人.


das*_*ght 23

Swift书有以下注释:

您必须始终将惰性属性声明为变量(使用var关键字),因为在实例初始化完成之后,可能无法检索其初始值.常量属性在初始化完成之前必须始终具有值,因此不能声明为惰性.

这在实现语言的上下文中是有意义的,因为在对象的初始化完成之前计算所有常量存储的属性.这并不意味着let当它与lazy它一起使用时可能已经改变了语义,但它还没有完成,所以在这一点上var仍然是唯一的选择lazy.

至于你提出的两个选择,我会根据效率决定它们:

  • 如果很少访问属性的值,并且预先计算是昂贵的,我会使用 var lazy
  • 如果在超过20..30%的情况下访问该值或计算相对便宜,我会使用 let

注意:我会进一步优化您的代码以将条件推送到CGFloat初始化程序:

let fontSize : CGFloat = CGFloat(someCase  ? 30 : 17)
Run Code Online (Sandbox Code Playgroud)

  • 您不需要`:CGFloat`,因为将推断出类型. (3认同)
  • 当语言实现细节影响抽象的逻辑时,我不喜欢它。Swift 中有很多令人讨厌的东西,缺少“lazy let”就是其中之一。 (2认同)

sdd*_*sma 10

正如dasblinkenlight所指出的那样,懒惰属性应始终在Swift中声明为变量.但是,有可能使属性为只读,因此它只能从定义实体的源文件中进行变换.这是我可以定义"懒惰"的最接近的.

private(set) lazy var fontSize: CGFloat = {
    if someCase {
        return 30
    } else {
        return 17
    }
}()
Run Code Online (Sandbox Code Playgroud)