按需静态计算?

时间:2016-10-22 12:48:01

标签: swift performance function static optional

我正在开发一个具有很多功能的课程。有些函数需要很多时间,因此我会将结果存储在创建中以供以后访问。但如果永远不需要这个值,那么计算就是浪费时间。

在这种情况下,如果已经计算了值,我将使用标记。如果是,请使用存储的值。如果没有,它将计算该值并将其存储在其静态变量中。

所以我需要函数本身,一个标记和一个保存结果的变量。每个功能有三个项目! 在Swift中是否存在类似于"可选的静态函数" ??

我更愿意使用

a = function()
每次通话都

。第一个调用将计算并保存结果,所有其他调用只会采用预先计算的结果(如缓存)。

1 个答案:

答案 0 :(得分:1)

延迟存储的属性

在下面的评论中,您描述了

  

但我并不是指全局静态值,而是针对每个实例。所以   如果您使用foo1foo2,则foo2需要计算自己的foo2   它本身的功能,因为它只取决于foo1的值。它   不能依赖之前完成的全球计算版本   按Foo。所以它就像一个“局部静态变量”

因此,似乎您可能对Foo的每个实例进行大量计算,并且您希望确保此计算最多执行一次,对于每个给定的{ {1}}。这个需求非常接近Swift中懒惰(存储)属性的定义:如果第一次调用以获取给定的lazy属性的值,则该属性将被实例化(例如,通过调用某个方法,执行一次只执行的闭包,或者只是通过给定的值/ literal),以及存储在属性中的值。对lazy属性的所有后续调用将仅使用存储的值(假设您不选择改变属性:lazy instance properties可能不是不可变的。)

例如,在实践中:

class Foo {
    lazy var bar: Int = self.reallyHeavyCalculation()
    lazy var baz: Int = {
        print("... heavy stuff")
        return 2 * self.baq
    }()

    private func reallyHeavyCalculation() -> Int {
        // ...
        print("... other heavy stuff")
        return 42
    }

    var bax: Int?
    var baq: Int // instance value used in once-only computation
                 // of (lazy) property baz: at baz instantiation

    init(baq: Int) { self.baq = baq }
}

let foo1 = Foo(baq: 50)

print("My first foo has never accessed his bar or baz")
foo1.bax = foo1.bar   // at first call: compute 'bar' for this Foo instance
var baxBaz = foo1.bar // 'foo1.bar' already computed
print(foo1.baz)       // at first call: compute 'baz' for this Foo instance
baxBaz = foo1.baz     // 'foo1.baz' already computed

/* Prints:
     My first foo has never accessed his bar or baz
     ... other heavy stuff
     ... heavy stuff
     100                                               */

静态属性总是懒惰地计算

(当我最初阅读你的问题时,我认为你的用例是类/静态属性,只计算一次。我将留下这部分答案,因为它仍然与这个主题,可能对未来的读者有所帮助)

静态属性总是懒惰地计算,这意味着它们只会使用给定至少一次调用的值进行实例化。在该实例化之后,例如,在静态不可变属性的情况下,只有一次计算的值很容易获得并存储在静态属性中。

我们可以阅读the Language Guide - Properties

  

输入属性

     

...

     

存储类型属性在首次访问时会被懒惰地初始化。   它们只保证初始化一次,即使访问时也是如此   多个线程同时进行,不需要标记   使用lazy修饰符。

     

...

     

全局和局部变量

     

...

     

全局常量和变量总是在a中懒惰地计算   与Lazy Stored Properties类似的方式。与懒惰存储不同   不需要标记属性,全局常量和变量   使用lazy修饰符。

我们可以通过简单的示例验证此行为:

class Foo {
    static let foo: Int = reallyHeavyCalculation() // lazy
    static let bar: Int = {
        print("... heavy stuff")
        return 99
    }() // lazy

    private static func reallyHeavyCalculation() -> Int {
        // ...
        print("... other heavy stuff")
        return 42
    }

    var bax: Int? = nil
    var baz = Foo.bar
}

print("I've never had a foo")

let foo1 = Foo()
    // first initializion of instance member 'baz' by 
    // type member 'bar': compute bar
print("I have a foo")
foo1.bax = Foo.foo // at first call: compute 'Foo.foo'

let foo2 = Foo() // 'Foo.bar' already computed
print("I have another foo")
foo2.bax = Foo.foo // 'Foo'foo' already computed


/* Prints:
     I've never had a foo
     ... heavy stuff
     I have a foo
     ... other heavy stuff
     I have another foo      */

在上面的示例中,如果您要求(至少一次)静态不可变属性{reallyHeavyComputation(),则Foo.bar(与Foo.foo)关联的闭包方法将被调用一次。 1}}(/ Foo.bar)。即使您反复要求reallyHeavyComputation()(/ Foo.foo)值,也不会对Foo.bar(/ closure)进行其他调用。

相关问题