提取Swift类的constant属性的初始化代码

时间:2019-02-20 02:12:59

标签: swift properties initialization

class Foo {
    let result: CGFloat

    init() {
        result = calculate()
    }

    private func calculate() -> CGFloat {
        // do many complex calculation with many codes
        return 0
    }
}

毫无疑问会发生错误。

  在所有存储的属性初始化之前,在方法调用“计算”​​中使用的

'self'

我知道几种解决此问题的方法。

  1. var而不是let。例如var result
  2. lazy。例如lazy result: CGFloat = { return 0 }
  3. calculate()设为class/static或全局函数。例如static func calculate()

但是我认为那不是我想要的。

为什么let

let表示不可变。尽管result的计算可能很复杂,但实际上是不可变的。因此,var并不是最佳实践。

为什么calculate()

init()中的代码太多,这不是惯用和烦人的

为什么不class/static

其他实例属性不能在静态函数中使用。


更新

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = calculate()
    }

    private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

为更加清楚,我添加了另一个代码段。实际上resultfoo3相同。那么,为什么foo3 = foo1 * foo2却是result = calculate()呢?

这是因为result(可能是10行代码)的计算比foo3(仅一行)的计算要复杂一些。如果我将所有这些代码都放在init()中,那将会很混乱。


尝试所有提及的方式

1。 var代替let

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    var result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = calculate()
    }

    private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

它可以工作,但是result并非一成不变。

2。 lazy

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    lazy var result: CGFloat = {
        calculate()
    }()

    init() {
        foo3 = foo1 * foo2
    }

    private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

它可以工作,但是result也不是不变的。

3。静态功能

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = Foo.calculate()
    }

    static private func calculate() -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

构建失败,

  

实例成员'foo3'不能用于类型'Foo'

4。关闭

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat
    private let calculate = { () -> CGFloat in
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }

    init() {
        foo3 = foo1 * foo2
        result = calculate()
    }
}

构建失败,

  

实例成员'foo3'不能用于类型'Foo'

5。计算属性

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    var result: CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }

    init() {
        foo3 = foo1 * foo2
    }
}

它可以工作,但是结果为'var',并且会针对每次使用情况进行计算。

6。工具类

class Foo {
    let foo1: CGFloat = 1.0
    let foo2: CGFloat = 2.0
    let foo3: CGFloat
    let result: CGFloat

    init() {
        foo3 = foo1 * foo2
        result = Tool.calculate(foo3: foo3)
    }
}

class Tool {
    static func calculate(foo3: CGFloat) -> CGFloat {
        // do some calculation
        let constants: CGFloat = 100
        // (10 lines...)
        return foo3 + constants
    }
}

它可以工作,但是我们引入了Tool类。

摘要

1、2、6是适当的。 6适合复杂的计算。

扩展名

多次提到“隐式展开的可选内容”。我很困惑为什么直到看到this answer

1 个答案:

答案 0 :(得分:1)

您未提及的另外两种方式是将app.Use(async (HttpContext context, Func<Task> next) => { context.Response.OnStarting(() => { context.Response.Headers.Add("X-Added-Key", "X-Added-Value"); return Task.CompletedTask; }); //await next(); try { await next(); } catch (Exception ex) { context.Response.StatusCode = 500; } }).UseMvc(); 变成其中一种

  • 一个隐式展开的可选
  • 计算属性

第三个是,将计算移至其自己的类型/自由函数,并提供至此类。可能是正确的解决方案。

Swift根本不允许您执行您要执行的操作:规则是必须设置所有存储的属性,然后才能对新实例的其他属性执行任何操作。坚决认为,任何无法证明正确的东西都必须被禁止。

例如,如果您将result更改为从calculate读取,该怎么办?或如果子类这样做了怎么办?您可能会遇到这样的情况,该值不仅是不确定的,而且是不确定的。