private(set) raises 'self' 在结构中是不可变的
private(set) raises 'self' is immutable within struct
我不知道我是不是太累了,但我认为还有更多。 (试了两杯咖啡,还是没能解决问题。。。)
我想从外部将变量设置为只读,但通过方法可写。 (所以就像在那个例子中一样,我可以确保 favoriteNumber 只是个位数。
(我不想让它成为计算的 属性 并在 get {}、set{} 中执行此操作,因为在我的其他项目中我想根据不同于以下值的值修改变量"newValue" 个集合 {})
struct Person {
var name: String
private(set) var favoriteNumber: Int? // Should only be single-digit
init(name: String, number: Int) {
self.name = name
// Make sure favorite number is single-digit
guard number >= 0 && number < 10 else {
self.favoriteNumber = nil
}
self.favoriteNumber = number
}
func changeFavoriteNumber(number: Int) {
guard number >= 0 && number < 10 else { return }
self.favoriteNumber = number
}
}
.
行
self.favoriteNumber = number
在函数中
changeFavoriteNumber(number:)
引发错误
"Cannot assign to property: 'self' is immutable"
并建议"Mark method 'mutating' to make 'self' mutable"。但这不是我想要的,因为我不想修改 Person 类型的实例,而是一个可变变量... (var favoriteNumber)
应该这样使用:
let frank = Person.init(name: "Frank", number: 9)
frank.changeFavoriteNumber(number: 8)
我不知道这里发生了什么(即使现在已经喝了 3 杯咖啡了:)
如果您不想使用 mutating
,那么您必须将 Person
设为 class
而不是 struct
。后者不允许突变,除非方法被标记为 mutable
并且实例是 var
变量而不是 let
变量。
为了完整起见,我还会提到使用 struct
解决此问题的方法,但我建议不要使用此解决方法。您可以 "box" 另一个(引用类型)对象中的 属性 值;这样你就可以掩盖突变。像这样:
class Box<T> {
var value: T
init(_ value: T) { self.value = value }
}
struct Person {
private var favoriteNumber: Box<Int> = Box(0)
func changeFavoriteNumber(_ number: Int) {
self.favoriteNumber.value = number
}
}
现在您可以使用 favoriteNumber.value
.
访问 Person
中的值
结构是值类型,与 classes 具有不同的语义。存储 class 实例的变量被存储为对内存中其他地方的实际对象的引用;这意味着您可以有两个指向同一个对象的变量,并且您可以修改 class 的成员,无论引用它的变量是否可变。
结构不同。存储 struct
实例的变量直接存储结构的成员,而不是作为对其他地方对象的引用。这意味着将结构传递给函数或另一个变量会创建它的副本,而修改 struct
会直接修改存储它的变量。
因此,结构是不可变的,除非它存储在 var
中。必须按照编译器的建议声明改变结构的函数 mutating
,以便编译器可以强制只在 let
结构上调用非改变函数。
您不应该像思考 类 那样思考结构。 swift 中的结构具有值语义。您不能更改使用 let 定义的结构的任何属性。尽管结构内部的属性是用 var 定义的,因为 origin 是用 let 定义的。
示例:
现在你可以这样做了:
frank.favoriteNumber = 10
但是如果你想改变一个结构的属性,因为它引用了值语义,你必须在你的函数中使用变异。变异是因为您正在改变结构的属性。
试试这个
变化:
mutating func changeFavoriteNumber(number: Int) {
guard number >= 0 && number < 10 else { return }
self.favoriteNumber = number
}
var frank = Person.init(name: "Frank", number: 9)
frank.changeFavoriteNumber(number: 8)
来自苹果文档:
从实例方法中修改值类型
结构和枚举是值类型。默认情况下,不能从其实例方法中修改值类型的属性。
但是,如果您需要在特定方法中修改结构或枚举的属性,则可以选择对该方法的行为进行更改。然后该方法可以从方法内部改变(即更改)其属性,并且它所做的任何更改都会在方法结束时写回原始结构。该方法还可以为其隐式自身 属性 分配一个全新的实例,并且该新实例将在该方法结束时替换现有实例。
您可以通过在该方法的 func 关键字之前放置 mutating 关键字来选择加入此行为:
URL
我不知道我是不是太累了,但我认为还有更多。 (试了两杯咖啡,还是没能解决问题。。。)
我想从外部将变量设置为只读,但通过方法可写。 (所以就像在那个例子中一样,我可以确保 favoriteNumber 只是个位数。
(我不想让它成为计算的 属性 并在 get {}、set{} 中执行此操作,因为在我的其他项目中我想根据不同于以下值的值修改变量"newValue" 个集合 {})
struct Person {
var name: String
private(set) var favoriteNumber: Int? // Should only be single-digit
init(name: String, number: Int) {
self.name = name
// Make sure favorite number is single-digit
guard number >= 0 && number < 10 else {
self.favoriteNumber = nil
}
self.favoriteNumber = number
}
func changeFavoriteNumber(number: Int) {
guard number >= 0 && number < 10 else { return }
self.favoriteNumber = number
}
}
.
行
self.favoriteNumber = number
在函数中
changeFavoriteNumber(number:)
引发错误
"Cannot assign to property: 'self' is immutable"
并建议"Mark method 'mutating' to make 'self' mutable"。但这不是我想要的,因为我不想修改 Person 类型的实例,而是一个可变变量... (var favoriteNumber)
应该这样使用:
let frank = Person.init(name: "Frank", number: 9)
frank.changeFavoriteNumber(number: 8)
我不知道这里发生了什么(即使现在已经喝了 3 杯咖啡了:)
如果您不想使用 mutating
,那么您必须将 Person
设为 class
而不是 struct
。后者不允许突变,除非方法被标记为 mutable
并且实例是 var
变量而不是 let
变量。
为了完整起见,我还会提到使用 struct
解决此问题的方法,但我建议不要使用此解决方法。您可以 "box" 另一个(引用类型)对象中的 属性 值;这样你就可以掩盖突变。像这样:
class Box<T> {
var value: T
init(_ value: T) { self.value = value }
}
struct Person {
private var favoriteNumber: Box<Int> = Box(0)
func changeFavoriteNumber(_ number: Int) {
self.favoriteNumber.value = number
}
}
现在您可以使用 favoriteNumber.value
.
Person
中的值
结构是值类型,与 classes 具有不同的语义。存储 class 实例的变量被存储为对内存中其他地方的实际对象的引用;这意味着您可以有两个指向同一个对象的变量,并且您可以修改 class 的成员,无论引用它的变量是否可变。
结构不同。存储 struct
实例的变量直接存储结构的成员,而不是作为对其他地方对象的引用。这意味着将结构传递给函数或另一个变量会创建它的副本,而修改 struct
会直接修改存储它的变量。
因此,结构是不可变的,除非它存储在 var
中。必须按照编译器的建议声明改变结构的函数 mutating
,以便编译器可以强制只在 let
结构上调用非改变函数。
您不应该像思考 类 那样思考结构。 swift 中的结构具有值语义。您不能更改使用 let 定义的结构的任何属性。尽管结构内部的属性是用 var 定义的,因为 origin 是用 let 定义的。
示例: 现在你可以这样做了:
frank.favoriteNumber = 10
但是如果你想改变一个结构的属性,因为它引用了值语义,你必须在你的函数中使用变异。变异是因为您正在改变结构的属性。 试试这个 变化:
mutating func changeFavoriteNumber(number: Int) {
guard number >= 0 && number < 10 else { return }
self.favoriteNumber = number
}
var frank = Person.init(name: "Frank", number: 9)
frank.changeFavoriteNumber(number: 8)
来自苹果文档:
从实例方法中修改值类型 结构和枚举是值类型。默认情况下,不能从其实例方法中修改值类型的属性。 但是,如果您需要在特定方法中修改结构或枚举的属性,则可以选择对该方法的行为进行更改。然后该方法可以从方法内部改变(即更改)其属性,并且它所做的任何更改都会在方法结束时写回原始结构。该方法还可以为其隐式自身 属性 分配一个全新的实例,并且该新实例将在该方法结束时替换现有实例。 您可以通过在该方法的 func 关键字之前放置 mutating 关键字来选择加入此行为: URL