gpt4 book ai didi

swift - 提取 Swift 类常量属性的初始化代码

转载 作者:可可西里 更新时间:2023-11-01 01:50:30 25 4
gpt4 key购买 nike

class Foo {
let result: CGFloat

init() {
result = calculate()
}

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

毫无疑问,错误发生了。

'self' used in method call 'calculate' before all stored properties are initialized`

我知道有几种方法可以解决这个问题。

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

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

为什么

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 * foo2result = 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。 懒惰

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
}
}

构建失败,

Instance member 'foo3' cannot be used on type '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()
}
}

构建失败,

Instance member 'foo3' cannot be used on type '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 .

最佳答案

您没有提到的其他两种方法是将 result 变成其中一种

  • 一个隐式解包的可选
  • 计算属性

第三种是,将计算移动到它自己的类型/自由函数中,并将其提供给这个类。这可能是正确的解决方案。

Swift 根本不允许你做你想做的事:规则是在你对新实例的其他属性做任何事情之前,必须设置所有存储的属性。它采取强硬的观点,即任何不能证明是正确的都必须被禁止。

例如,如果您将 calculate 更改为从 result 中读取会怎样?或者如果子类这样做了怎么办?您会遇到值不仅未定义而且无法定义的情况。

关于swift - 提取 Swift 类常量属性的初始化代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54777833/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com