我对使用 lazy 功能的位置感到困惑,我的意思是说我应该在集合中使用 lazy 关键字来处理哪种类型的条件。
答案 0 :(得分:1)
延迟评估是指延迟表达式的评估,直到需要结果为止。这与渴望评估相反,后者是对表达式的评估立即进行的。
考虑这个表达式:
let input = [1, 2, 3]
let evens = input.map{ $0 * 2 }
闭包{ $0 * 2 }
将每个数字(1,2,3)映射到一个新值,将它们乘以2.这个评估是急切的。也就是说,执行此行的时刻是执行map
函数的评估,并且计算结果存储在evens
中。 input
的类型为Array<Int>
,结果evens
的类型为Array<Int>
。
现在考虑一下这个表达式:
let input = [1, 2, 3]
let evens = input.lazy.map{ $0 * 2 }
闭包{ $0 * 2 }
的每个数字(1,2,3)将一个新值,它们将它们乘以2.但是,这个评估是懒惰的。也就是说,在执行此行时,不会进行乘法运算。而是存储闭包{ $0 * 2 }
以供将来参考。 input
的类型为Array<Int>
,结果evens
的类型为LazyMapRandomAccessCollection<Array<Int>, Int>
。乘法推迟到元素访问。如果永远不会访问某个元素,那么它永远不会被处理。
在这种微不足道的情况下,存储关闭以供将来评估的簿记开销将大于仅仅急切地计算结果。但是,您可以设想这样的情况:
let input = 1...1000000000
let evens = input.lazy.map{ $0 * 2 }
print(evens[0])
在序列中的所有1000000000
中,只有一个被使用过。评估闭包1000000000
次,产生1000000000
结果,将它们全部存储在内存中是非常低效的,如果只需要第一个元素。
lazy
是Sequence
协议的实例方法。所有符合类型的类型,包括NSMutableDictionary
都会实现它。它们都做同样的事情:它们推迟处理map
和filter
语句中的元素,直到需要它们的结果为止。在有许多元素的情况下,这可以节省内存和处理时间,并且只需要一小部分元素。
答案 1 :(得分:1)
来自Apple Docs:
惰性存储属性是一个属性,其初始值在第一次使用之前不会计算。通过在声明之前编写惰性修饰符来指示延迟存储的属性。
使用@lazy
属性时,请记住以下内容:
var
关键字声明,而不是使用let
常量声明。 我们如何在Objective-C中实现延迟功能
@property (nonatomic, strong) NSMutableArray *players;
- (NSMutableArray *)players
{
if (!_players) {
_players = [[NSMutableArray alloc] init];
}
return _players;
}
现在在Swift中,您可以使用lazy
属性实现相同的功能。见下面的例子
class Person {
var name: String
lazy var personalizedGreeting: String = {
return "Hello, \(self.name)!"
}()
init(name: String) {
self.name = name
}
}
现在,当您初始化某个人时,尚未创建他们的个人问候语:
let person = Person(name: "John Doe") // person.personalizedGreeting is nil
但是当您尝试打印个性化问候语时,它会即时计算:
print(person.personalizedGreeting)
// personalizedGreeting is calculated when used
// and now contains the value "Hello, John Doe!"
我希望这有助于您了解懒惰属性的功能。
答案 2 :(得分:0)
延迟工作的方式是初始化程序(或init方法)仅在首次访问变量或属性时运行。我看到在你的代码中它不能工作(至少是直接)的一个主要原因,那是因为你将两个惰性实例化代码打包到一个方法中(loadEntriesIfNeeded)。
要使用延迟实例化,您可能需要扩展NSMutableArray和NSDictionary,并为您的延迟实例化覆盖或创建自定义初始化程序。然后,将loadEntriesIfNeeded中的代码分发到各自的初始值设定项中。
import Swift
println("begin")
class ClassWithLazyProperties {
lazy var entries:[String] = ClassWithLazyProperties.loadStuff()
lazy var entriesByNumber:Dictionary<Int, String> = {
var d = Dictionary<Int, String>()
for i in 0..<self.entries.count {
d[i] = self.entries[i]
}
return d
}()
private class func loadStuff() -> [String] {
return ["Acai", "Apples", "Apricots", "Avocado", "Ackee", "Bananas", "Bilberries"]
}
}
let c = ClassWithLazyProperties()
c.entriesByNumber
// 0: "Acai", 1: "Apples", 2: "Apricots", 3: "Avocado", 4: "Ackee", 5: "Bananas", 6: "Bilberries"]
println("end")