例如:
var dogName : String {
return "Buster"
}
VS ..
let dogName = "Buster"
假设我们将类中的每一个声明为实例属性。这些只是做同样事情的两种方式吗?如果没有,那么拥有只读变量有什么意义呢?
由于
答案 0 :(得分:6)
让我试着总结其他答案所说的内容,同时添加我认为对于理解这一点至关重要的缺失信息。
属性只是与对象关联的值,可以在很短的时间内查询,而不需要(或能力)方法等参数。
当您创建存储属性时,无论是let
还是var
,在任何给定时间点分配的值都将存储在内存中,这就是它被称为存储属性的原因。 / p>
var name = "Matt"
对于使用var
的变量,该值以一种使其可变(可编辑)的方式存储在内存中。您可以随意重新分配该值,它将替换之前的值存储在内存中。
let name = "Matt"
对于使用let
的常量,该值也会存储在内存中,但是在第一次分配后可能无法更改。
计算属性不存储在内存中。正如ganzogo在评论中所说,计算属性的行为与方法类似,但不采用参数。在决定何时使用计算属性或没有参数的函数时,Swift API设计指南建议在简单地创建或获取时使用计算属性,然后返回该值,前提是这需要花费很少的时间。 / p>
var fullName: String {
return firstName + lastName
}
在这里,我们假设firstName
和lastName
已经是对象的属性。这个属性没有初始化的意义,因为它没有存储在任何地方。它是按需每次获取的。这就是为什么没有意义做以下事情:
var dogName : String {
return "Buster"
}
这对存储的属性没有任何好处,除了在存储String
“Buster”时不会使用任何内存。
实际上,这是计算属性的简化版本。您会注意到Swift语言指南描述了计算属性中get
和set
的使用。 set
允许您在设置计算变量时更新其他变量的状态。例如:
var stored: Int
var computed: Int {
get {
return stored + 5
}
set {
stored = newValue - 5
}
}
Rajan的回答指出了一些有用的应用,例如从width
,height
和depth
获取和设置音量。
只读计算var只是一个计算的var,它只指定一个getter,在这种情况下,get
关键字和括号不是必需的。
在开发框架等模块时,通常只需要在该对象或框架内修改变量并使其对公众只读即可。
private var modifiableItem: String
public var item: String {
return modifiableItem
}
这里的想法是modifiableItem
只能在定义它的对象中变化。 private
关键字确保它只能在创建它的对象的范围内访问,并使其成为var
,以确保它可以被修改。那么,public var item
是一个向公众公开的计算变量,使任何人都可以阅读,但不能改变变量。
正如Hamish在评论中指出的那样,使用private(set)
更简洁地表达了这一点:
public private(set) var item: String
这可能是最好的解决方法,但前面的代码(使用私有存储属性和公共计算属性)证明了这种效果。
答案 1 :(得分:3)
let dogName = "Buster"
表示dogName
变量一旦被分配"Buster"
后就无法更改,并且变为常量
var dogName : String {
return "Buster"
}
它是一个计算只读属性,您可以在其中进行一些计算,因为它是一个var,但是以下面定义的方式进行更改:
可以像
一样更改计算属性var dogName : String {
return "Stress"+"Buster"
}
从Apple Docs
中考虑此示例struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
会打印
// Prints "the volume of fourByFiveByTwo is 40.0"
这里,在初始化struct Cuboid
的对象时计算卷,并在运行时计算。如果它被释放,那么你必须先使用一些常量来初始化它。
如果您想了解更多相关信息,请阅读计算属性部分here
答案 2 :(得分:1)
类/结构中的只读属性意味着您无法更改类/结构的该实例的属性值。它阻止我做:
someObject.dogName = "Buddy" // This fails - read-only property
但是,我仍然可以这样做:
var someVariable = someObject.dogName // someVariable now is "Buster"
someVariable = "Buddy" // This is OK, it's now "Buddy"
let
常量意味着您不会在该代码块中更改该特定常量的值。
let someName = "Buster"
someName = "Buddy" // This fails - someName is a constant
答案 3 :(得分:1)
在你的例子中,他们是做同样事情的两种方式。但是,您可以使用计算属性执行更多操作。例如:
var dogName: String {
return firstName + " " + lastName
}
此处,firstName
和lastName
在初始化时可能不知道。对于简单的let
属性,这是不可能的。
您可能会将计算属性视为没有参数的方法。
答案 4 :(得分:0)
有两种不同的情况:
1)值类型:
struct DogValueType {
var name: String
}
let dog1 = DogValueType(name: "Buster")
var dog2: DogValueType {
return DogValueType(name: "Buster")
}
let dog3: DogValueType = {
return DogValueType(name: "Buster")
}()
dog1
- dog3
无法更改或变异dog1
& dog3
存储值dog3
都会计算值2)参考类型:
class DogReferenceType {
var name: String
init(name: String) {
self.name = name
}
}
let dog4 = DogReferenceType(name: "Buster")
var dog5: DogReferenceType {
return DogReferenceType(name: "Buster")
}
let dog6: DogReferenceType = {
return DogReferenceType(name: "Buster")
}()
dog4
- dog6
无法更改,但可以进行变异dog4
& dog6
存储对象的引用。dog5
每次访问时都会创建对象