每次访问计算属性时都会对其进行评估吗?

Posted

技术标签:

【中文标题】每次访问计算属性时都会对其进行评估吗?【英文标题】:Are computed properties evaluated every time they are accessed? 【发布时间】:2016-05-06 01:46:58 【问题描述】:

我有两个关于 Swift 计算属性的问题。

或者它们存储在某个地方以备将来访问?

这是什么属性,我google也搜不出来:

let navigationController: UINavigationController = 
   var navigator = UINavigationController()
   navigator.navigationBar.translucent = false
   return navigator
()

每次访问时也会评估它吗?

【问题讨论】:

【参考方案1】:

这不是计算属性。

let navigationController: UINavigationController = 
   var navigator = UINavigationController()
   navigator.navigationBar.translucent = false
   return navigator
()

它只是一个存储属性,填充了这段代码返回的值的结果。

var navigator = UINavigationController()
navigator.navigationBar.translucent = false
return navigator

当类的实例被实例化时,块被执行。只有一次。

所以写这个

struct Person 
    let name: String = 
        let name = "Bob"
        return name
    () // <- look at these

与此等价

struct Person 
    let name: String
    init() 
        self.name = "Bob"
    

恕我直言,第一种方法更好,因为:

它确实允许您在相同的“空间”中声明和填充属性 更清晰 如果您有多个初始化程序,确实可以防止重复代码

注意 #1:在属性中存储闭包

正如 dfri 在下面的评论中指出的那样,代码块确实以 () 结尾。这意味着代码已求值并将结果分配给属性。

另一方面,如果我们删除块末尾的(),我们会得到不同的结果,实际上该块是评估的。 在这种情况下,Swift 尝试将 stored closure 分配给该属性。这将产生编译错误,因为该属性的类型为 UINavigationController

使用正确的语法,我们可以在属性中放置一个闭包。

struct Person 
    let sayHello: ()->() =  print("Hello") 

现在我们有了一个包含闭包的sayHello 属性。闭包接收 0 个参数并返回 Void

let bob = Person()
bob.sayHello // this does NOT execute the code inside closure
bob.sayHello() // this does execute the code in the closure and does print the message

注意 #2:让我们谈谈计算属性

所以我们明确指出,这个问题中的代码不是Computed Property。 但是,正如 EmilioPelaez 在下面的另一条评论中指出的那样,我们还应该声明Computed Property每次被访问时都会被评估。

在下面的示例中,我创建了一个计算属性age。正如你所看到的,每次我调用它时,块中的代码也会被执行。

计算属性示例 (age)

【讨论】:

是的,代码只执行一次。您可以在该代码块中添加print("Test") 并验证它。 可能值得一提的是,最后大括号后的() 是这里的关键(通过运行匿名闭包块来初始化navigationController 属性)。例如。删除最后的()“稍微” 将顶行修改为let navigationController: () -&gt; (UINavigationController) = ... 将产生一个存储的闭包,该闭包返回UINavigationController 实例和.translucent = false。这个闭包又可以用来代替上面的匿名块,即用闭包名称代替 ... 块:let myNavigationController = navigationController() @dfri:我完全同意。我会在我的回答中加入这个考虑。谢谢。 第一个问题的答案也应该加上,计算机属性每次访问都是计算机。 @appzYourLife 最后一点:我删除了(),但还必须将UINavigationController 类型替换为闭包类型... : () -&gt; (UINavigationController) = ...,而不是之前的... : UINavigationController = ...。如果我们在这里只删除(),我们会得到一个编译时错误。但是,我们可以将显式类型排除在外,让 Swift 来推断这些类型,例如对于let foo = () -&gt; Int in 1 (),最终的() 是将1 分配给foo(包括最终的(),=> fooInt)或将() -&gt; Int 闭包分配给foo 之间的唯一区别(省略())。

以上是关于每次访问计算属性时都会对其进行评估吗?的主要内容,如果未能解决你的问题,请参考以下文章

关于枚举/列表的评估[重复]

Python类设置器 - 每次创建新实例时都会重新分配类属性吗?

Vue中的methods属性和computed属性的区别

类的惰性属性

在Csharp中,我如何计算每次单击特定按钮时都会增加的某个值

computed和watch的使用场景