「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战」
Swift语言中的属性从行为上可以分为存储属性和计算属性两类。存储属性和计算属性的区别在于:存储属性用于描述存储值,而计算属性用于描述计算过程并获取计算结果;
存储属性
存储属性用来定义类或者结构体的某些特性,其实我们在之前使用结构体和类的时候,就已经在使用存储属性描述事物的特征了。简单来说就是用变量var或者常量let存储的某些有意义的值;
比如下边示例:
class Person {
// 姓名和年级为变量存储属性,可以进行修改
var name: String
var age: Int
// 性别为常量存储属性,一旦实例被构造,则不能再次修改;
let sex: String
}
Person类中的name、age和sex都是我们所说的存储属性;name和age我们使用var来声明,它们就是变量,可以在将来设置为不同的值;sex我们使用let来声明,它就是常量,一旦设置之后,值不能被更改;
在类中有一个原则:当类实例被构造完成时,必须保证类中所有的属性都构造或者初始化完成。因此,一般情况下我们会在创建的类中提供一个构造方法用来设置其中的属性,比如上述代码在编译器中其实是会报错的:
我们必须为Person类提供一个构造方法,通过构造方法确保Person类的属性能够被初始化:
但并不是所有的情况都需要这么做,我们也可以为类中的属性在声明时就提供一个初始值,如下代码,给childhoodName属性设置默认值:
由于name和age是使用var声明的,因此其可以在初始化之后被再次修改,而sex是被let声明的,因此初始化之后,不能再次修改:
因为实例对象p我们也使用了let来声明,因此p被创建之后,也不能再次被修改:
let和var分析
那么let和var的可修改和不可修改到底是有什么决定的呢?我们分别定义如下的age和sex:
我们通过生成SIL文件来分析其区别:
我们看到使用var声明的age,在SIL中生成了set和get方法;而let声明的sex只生成了get方法;因此再次给sex赋值时实际是调用set方法,但是因为找不到set方法,所以无法再次赋值;
var和let本质上也是语法糖;
计算属性
与存储属性相比,计算属性更像是运算过程,计算属性并不存储值,而是提供get和set方法来修改和获取值。存储属性我们可以定义常量或者是变量,但是对于计算属性,必须定义为变量,并且计算属性在定义时必须包含类型;
比如以下示例代码:
对于Struct来说,计算属性area本质上是一个方法,方法不占用结构体的内存空间;此处的newValue是编译器自动生成的,这点我们可以从SIL中看到:
也可以通过如下方式修改:
我们将代码修改如下:
将height修改为常量,将area修改为只读的计算属性,我们通过SIL分析其区别:
我们可以看到let的存储属性没有set方法,只读的计算属性area也没有set方法;所以我们不能简单的通过有没有**set**方法来区分属性是计算属性还是存储属性;同时我们可以发现,对于计算属性来说,set方法是可选的,而get方法必不可少;