包含延迟初始化器的 Swift 结构的初始化问题
Initialization problem with Swift struct that contains lazy initializers
我为在线编程练习网站上的 Swift 编程练习编写了两个版本的代码。练习如下:
Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.
The square of the sum of the first ten natural numbers is (1 + 2 + ... + 10)² = 55² = 3025.
The sum of the squares of the first ten natural numbers is 1² + 2² + ... + 10² = 385.
Hence the difference between the square of the sum of the first ten natural numbers and the sum of the squares of the first ten natural numbers is 3025 - 385 = 2640.
第一个版本的代码是:
struct Squares {
let squareOfSum : UInt64
let sumOfSquares : UInt64
let differenceOfSquares : UInt64
init(_ number: UInt64) {
var sum = ((1 + number) * number) / 2
squareOfSum = sum * sum
sum = 0
for i in 1...number {
sum = sum + (UInt64)(i * i)
}
sumOfSquares = sum
differenceOfSquares = squareOfSum - sumOfSquares
}
}
let sqrs = Squares(5)
print(sqrs.differenceOfSquares)
它顺利通过了编译和 运行s。
第二个版本的代码是:
struct Squares {
let num : UInt64
lazy var squareOfSum: UInt64 = {
return ((1...num).reduce(0, +)).squared
}()
lazy var sumOfSquares: UInt64 = {
return ((1...num).map{[=12=].squared}).reduce(0, +)
}()
lazy var differenceOfSquares: UInt64 = {return squareOfSum - sumOfSquares }()
init(_ number: UInt64) {
num = number
}
}
extension Numeric {
var squared: Self {
return self * self
}
}
let sqrs = Squares(5)
print(sqrs.differenceOfSquares)
编译代码时,编译器会生成以下消息:
/tmp/0C9C2EC3-543D-486F-BCB0-D181EC48DC82.8NCVch/main.swift:25:7: error: cannot use mutating getter on immutable value: 'sqrs' is a 'let' constant
print(sqrs.differenceOfSquares)
^~~~
/tmp/0C9C2EC3-543D-486F-BCB0-D181EC48DC82.8NCVch/main.swift:24:1: note: change 'let' to 'var' to make it mutable
let sqrs = Squares(5)
^~~
var
如果我根据编译器的建议将 let
更改为 var
for sqrs
,代码将 运行 很好。或者,如果我将类型 struct
更改为 class
以使对象可变,代码也将 运行 很好。但是,在我的第一个版本的代码中,struct
对象和 let
可变定界符的组合没有问题。怎么到了第二个版本,这两个就变得不协调了?虽然我不知道为什么,但我怀疑这可能与第二个版本中的惰性初始化程序有关。
谁能帮忙解释一下?非常感谢您。
惰性属性具有可变的 getter,即访问惰性 属性 可能会改变结构。为什么?想想你第一次访问一个懒惰的属性。在第一次访问之前,那个属性没有值,在你访问它之后,=
右边的表达式被计算并赋值给属性。现在 属性 有了一个值。这就是访问惰性 属性 可以更改结构的方式。因此,您需要 var
才能访问惰性属性。
将结构更改为 class 也有帮助,因为现在 sqrs
存储引用,而 let sqrs
仅使 reference对象常量,而不是使对象本身常量。
第一个版本初始化初始化器中的所有属性。您可以在初始化程序中为每个 let
属性 分配一次,这是第一个版本所做的。由于第一个版本中的属性不是惰性的,您可以使用 let
常量访问它们。
我为在线编程练习网站上的 Swift 编程练习编写了两个版本的代码。练习如下:
Find the difference between the square of the sum and the sum of the squares of the first N natural numbers. The square of the sum of the first ten natural numbers is (1 + 2 + ... + 10)² = 55² = 3025. The sum of the squares of the first ten natural numbers is 1² + 2² + ... + 10² = 385. Hence the difference between the square of the sum of the first ten natural numbers and the sum of the squares of the first ten natural numbers is 3025 - 385 = 2640.
第一个版本的代码是:
struct Squares {
let squareOfSum : UInt64
let sumOfSquares : UInt64
let differenceOfSquares : UInt64
init(_ number: UInt64) {
var sum = ((1 + number) * number) / 2
squareOfSum = sum * sum
sum = 0
for i in 1...number {
sum = sum + (UInt64)(i * i)
}
sumOfSquares = sum
differenceOfSquares = squareOfSum - sumOfSquares
}
}
let sqrs = Squares(5)
print(sqrs.differenceOfSquares)
它顺利通过了编译和 运行s。
第二个版本的代码是:
struct Squares {
let num : UInt64
lazy var squareOfSum: UInt64 = {
return ((1...num).reduce(0, +)).squared
}()
lazy var sumOfSquares: UInt64 = {
return ((1...num).map{[=12=].squared}).reduce(0, +)
}()
lazy var differenceOfSquares: UInt64 = {return squareOfSum - sumOfSquares }()
init(_ number: UInt64) {
num = number
}
}
extension Numeric {
var squared: Self {
return self * self
}
}
let sqrs = Squares(5)
print(sqrs.differenceOfSquares)
编译代码时,编译器会生成以下消息:
/tmp/0C9C2EC3-543D-486F-BCB0-D181EC48DC82.8NCVch/main.swift:25:7: error: cannot use mutating getter on immutable value: 'sqrs' is a 'let' constant
print(sqrs.differenceOfSquares)
^~~~
/tmp/0C9C2EC3-543D-486F-BCB0-D181EC48DC82.8NCVch/main.swift:24:1: note: change 'let' to 'var' to make it mutable
let sqrs = Squares(5)
^~~
var
如果我根据编译器的建议将 let
更改为 var
for sqrs
,代码将 运行 很好。或者,如果我将类型 struct
更改为 class
以使对象可变,代码也将 运行 很好。但是,在我的第一个版本的代码中,struct
对象和 let
可变定界符的组合没有问题。怎么到了第二个版本,这两个就变得不协调了?虽然我不知道为什么,但我怀疑这可能与第二个版本中的惰性初始化程序有关。
谁能帮忙解释一下?非常感谢您。
惰性属性具有可变的 getter,即访问惰性 属性 可能会改变结构。为什么?想想你第一次访问一个懒惰的属性。在第一次访问之前,那个属性没有值,在你访问它之后,=
右边的表达式被计算并赋值给属性。现在 属性 有了一个值。这就是访问惰性 属性 可以更改结构的方式。因此,您需要 var
才能访问惰性属性。
将结构更改为 class 也有帮助,因为现在 sqrs
存储引用,而 let sqrs
仅使 reference对象常量,而不是使对象本身常量。
第一个版本初始化初始化器中的所有属性。您可以在初始化程序中为每个 let
属性 分配一次,这是第一个版本所做的。由于第一个版本中的属性不是惰性的,您可以使用 let
常量访问它们。