包含惰性初始值设定项的Swift结构的初始化问题
我在一个在线编程练习网站上为Swift编程练习编写了两个版本的代码。行动如下: 求和的平方与前N个自然数的平方和之间的差。 前十个自然数之和的平方为(1+2+…+10)²=55²=3025。 前十个自然数的平方和为1²+2²+…+10² = 385. 因此,前十个自然数的平方和与前十个自然数的平方和之间的差值为3025-385=2640 第一个版本的代码是:包含惰性初始值设定项的Swift结构的初始化问题,swift,class,struct,lazy-initialization,mutating-function,Swift,Class,Struct,Lazy Initialization,Mutating Function,我在一个在线编程练习网站上为Swift编程练习编写了两个版本的代码。行动如下: 求和的平方与前N个自然数的平方和之间的差。 前十个自然数之和的平方为(1+2+…+10)²=55²=3025。 前十个自然数的平方和为1²+2²+…+10² = 385. 因此,前十个自然数的平方和与前十个自然数的平方和之间的差值为3025-385=2640 第一个版本的代码是: struct Squares { let squareOfSum : UInt64 let sumOfSquares :
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)
struct Squares {
let num : UInt64
lazy var squareOfSum: UInt64 = {
return ((1...num).reduce(0, +)).squared
}()
lazy var sumOfSquares: UInt64 = {
return ((1...num).map{$0.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)
它通过了编译,运行起来没有问题
第二个版本的代码是:
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)
struct Squares {
let num : UInt64
lazy var squareOfSum: UInt64 = {
return ((1...num).reduce(0, +)).squared
}()
lazy var sumOfSquares: UInt64 = {
return ((1...num).map{$0.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
如果按照编译器的建议,将sqrs
的let
更改为var
,代码将运行良好。或者,如果我将类型struct
更改为class
,以使对象可变,那么代码也会运行良好。但是,在我的第一个版本中的代码中,struct
对象和let
可变定界符的组合没有问题。为什么在第二个版本中,这两个变得不一致?虽然我不知道为什么,但我怀疑这可能与第二个版本中懒惰的初始值设定者有关
谁能帮我解释一下吗?非常感谢您。惰性属性具有变异的getter,即访问惰性属性可能会变异结构。为什么?想想你第一次访问一个懒惰的属性。在第一次访问之前,该属性没有值,访问之后,将计算
=
右侧的表达式并将其指定给该属性。现在属性有了一个值。这就是访问惰性属性可以改变结构的方式。因此,您需要一个var
来访问惰性属性
将结构更改为类也会有所帮助,因为现在sqrs
存储引用,而让sqrs
仅使对对象的引用保持不变,而不是使对象本身保持不变
第一个版本初始化初始化器中的所有属性。您可以在初始化器中为每个
let
属性指定一次,这是第一个版本所做的。由于属性在第一个版本中不是惰性的,因此您可以使用let
常量来访问它们。谢谢您,Sweeper,您的清晰解释有助于我理解问题。因此,您的意思是,就lazy
初始化而言,lazy
属性被访问并分配给的那一刻,struct
作为一个整体被改变,以至于它不能被分配给struct
的常量引用,即使是第一次?如果是这样,语言的灵活性将是一个遗憾。无论如何,在现实生活中,安全性可能会压倒所有其他因素。