小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
我们通过一个例子来引入什么是值类型
func test(){
//栈区声明一个地址,用来存储age变量
var age = 18
//传递的值
var age2 = age
//age、age2是修改独立内存中的值
age = 30
age2 = 45
print("age=(age),age2=(age2)")
}
test()
从例子中可以得出,age存储在栈区
-
查看
age的内存情况,从图中可以看出,栈区直接存储的是值- 获取age的栈区地址:
po withUnsafePointer(to: &age){print($0)} - 查看age内存情况:
x/8g 0x00007ffeefbff3e0
- 获取age的栈区地址:
- 查看
age2的情况,从下图中可以看出,age2的赋值相当于将age中的值拿出来,赋值给了age2。其中age与age2的地址 相差了8字节,从这里可以说明栈空间是连续的、且是从高到低的
所以,从上面可以说明,age就是值类型
值类型 特点
- 1、地址中存储的是
值 - 2、值类型的传递过程中,相当于
传递了一个副本,也就是所谓的深拷贝 - 3、值传递过程中,并不共享状态
结构体
结构体的常用写法
//***** 写法一 *****
struct CJLTeacher {
var age: Int = 18
func teach(){
print("teach")
}
}
var t = CJLTeacher()
//***** 写法二 *****
struct CJLTeacher {
var age: Int
func teach(){
print("teach")
}
}
var t = CJLTeacher(age: 18)
- 在结构体中,如果不给属性默认值,编译是不会报错的。即在结构体中属性可以赋值,也可以不赋值
init方法可以重写,也可以使用系统默认的
为什么结构体是值类型?
定义一个结构体,并进行分析
struct CJLTeacher {
var age: Int = 18
var age2: Int = 20
}
var t = CJLTeacher()
print("end")
打印t:po t,从下图中可以发现,t的打印直接就是值,没有任何与地址有关的信息
- 获取t的内存地址,并查看其内存情况
- 获取地址:
po withUnsafePointer(to: &t){print($0)} - 查看内存情况:
x/8g 0x0000000100008158
- 获取地址:
问题:此时将t赋值给t1,如果修改了t1,t会发生改变吗?
- 直接打印t及t1,可以发现t并没有因为t1的改变而改变,主要是因为因为
t1和t之间是值传递,即t1和t是不同内存空间,是直接将t中的值拷贝至t1中。t1修改的内存空间,是不会影响t的内存空间的
总结
结构体是值类型,且结构体的地址就是第一个成员的内存地址- 值类型
- 在内存中直接
存储值 - 值类型的赋值,是一个
值传递的过程,即相当于拷贝了一个副本,存入不同的内存空间,两个空间彼此间并不共享状态 值传递其实就是深拷贝
- 在内存中直接