【问题标题】:Swift: why aren't all variables lazy by default?Swift:为什么默认情况下不是所有变量都是惰性的?
【发布时间】:2016-04-22 20:49:34
【问题描述】:

比较定义实例属性的这两个选项:

var networkManager = NetworkManager.sharedInstance()

var lazy networkManager = NetworkManager.sharedInstance()

两者:

  • 可以评估块以获取值
  • 可以内联声明(不是块,如上)

懒惰:

  • 可以参考自己
  • 直到需要才计算
  • 如果你不使用它,它永远不会被计算

非懒惰:

  • 没有任何好处

使用非惰性变量似乎没有任何好处。那么为什么语言允许程序员做出这种劣等的选择呢?

(我不是在问 var 和 let à la Are Swift constants lazy by default? 之间的区别)

【问题讨论】:

  • 坦率地说,lazy 初始化是要避免的。它在应用程序中引入了非确定性行为,并且是永无止境的调试冒险的源泉。它还使重构变得更加困难,因为每次更改都有可能由于意外的行为更改而导致无法预料的更改。
  • @FullDecent “类属性”不是正确的术语,Swift 中没有这样的东西(在说话的时候)。有实例属性和类型属性……
  • 添加到上层 cmets:它应该是可选的,因为您不希望看到一些性能影响,因为在子例程开始时分配内存。大多数情况下,速度太重要了。而且在调试方面,如果它是默认的,那将是一件很痛苦的事情。
  • @Whirlwind 谢谢更新
  • 这也可能是一个原因:If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.

标签: swift


【解决方案1】:

一个原因可能是惰性不适合您想要控制何时评估发生的情况。这在作业中完成的工作有副作用的情况下是相关的。

虽然这与关闭有关,但 stuart sierra 的博客 post 很好地解释了这个想法,我认为它同样适用于任何语言。

【讨论】:

    【解决方案2】:

    正如其他人已经说过的,有几个关键场景您希望属性的初始化是确定性

    这是一个与游戏开发相关的示例(以及许多其他示例)。

    通常代表游戏场景/关卡中项目的类实例是在关卡开始之前创建的。

    初始化可能是一项耗时的任务(从持久存储中加载内容、分配内存、准备实例...),在玩家开始玩关卡之前完成这部分确实可以避免 CPU 开销 .

    这很关键,因为在关卡中间的 CPU 开销可能会导致帧速率下降,这对用户体验来说是一场噩梦。

    【讨论】:

      【解决方案3】:

      仅供参考。我的感觉是 Swift 想要变得更像一种函数式语言,并且希望在更多地方实现惰性实例化。

      My early assessment of Swift 随着时间的推移一直保持得很好(嗯,“非功能性”部分。我没想到 Swift 在以后的版本中会偏爱方法而不是函数)。 Swift 不是一种函数式语言,也不打算成为一种语言。这在 WWDC 会谈、论坛、Twitter 以及与 Swift 团队的对话中经常出现。最初所有的地图和过滤器都是惰性的。斯威夫特删除了它,因为它引起的问题。可能关于该主题的最佳演讲是"Building Better Apps with Value Types in Swift"。正如他们所说:

      我们喜欢突变。我们认为它很有价值。我们认为如果操作正确,它很容易使用。

      没有比这更多的“非功能性”了。 Swift 还包含不可变数据。但函数式编程是关于不可变数据上的纯函数,这不是 Swift。

      (当然有很多非惰性函数式语言。惰性和函数式是正交的概念。Haskell 恰好同时包含这两者。)

      不过,对于手头的问题:

      我发现lazy 属性在现实世界的 Swift 中很少有用(我很慷慨;我从未遇到过将它保留在代码中的情况)。它没有像您在 Haskell 中获得的懒惰那样提供任何东西。 It isn't thread safe, 所以这是一场噩梦。它强制你进入引用类型(或强制你的结构是可变的),所以这可能很烦人。如果我听说他们将其从语言中提取出来,而我们只需要推出自己的语言,那对我来说很好。 (我很想为此写一个提案。)它实现了一种特定的备忘录模式,这种模式偶尔会很方便,但通常不是你想要的。所以它不是默认值是一件非常好的事情。

      您可能知道,默认情况下,全局变量和类变量 是惰性的,而且我认为这往往效果很好,因为它们的数量要少得多,它们的可能性更大在实践中不会被访问,并且惰性是线程安全的(这是有代价的,但由于它们非常罕见,因此成本要低得多)。

      【讨论】:

      • 感谢您的讨论,博客很棒。现在我是订阅者。仅供参考,我在引用类型中使用它:class networkManager { private let baseURL = "..."; private lazy var sessionManager: AFHTTPSessionManager = { let retval = AFHTTPSessionManager(baseURL: NSURL(string: self.SERVER_ECHO_API_URL)) ... }
      【解决方案4】:

      如果您有一个昂贵的对象(就创建时间而言,需要很长时间),您希望决定和控制何时创建它。有人可能会争辩说惰性变量应该是默认值。也许有历史原因。 ObjC 中的惰性属性导致大量样板代码。

      【讨论】:

      • 这不是很实用,但是_ = self.expensiveProperty 解决了这个问题吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-01
      • 2010-11-02
      • 1970-01-01
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      相关资源
      最近更新 更多