值类型
值类型赋值给var
let
或者给函数传参,是直接将所有内容拷贝一份
类似于对文件做copy
paste
操作,产生全新的文件副本,属于深拷贝deep copy
var p1 = Point(x: 10, y: 10)
var p2 = p1 //将p1的所有内容直接拷贝覆盖给p2,两个都在栈空间
p2.x = 11
p2.y = 22
//请问p1.x p1.y是多少
上面代码中的p1.x、p1.y
的值依然是10、10
,p2
的赋值不影响p1
的值
值类型的赋值操作
var s1 = "jack"
var s2 = s1
s2.append("_Rose")
print(s1) // jack
print(s2) //jack_Rose
var a1 = [1, 2, 3]
var a2 = a1
a2.append(4)
a1[0] = 2
print(a1) // [2, 2, 3]
print(a2) // [1, 2, 3, 4]
var d1 = ["max": 10, "min": 2]
var d2 = d1
d1["other"] = 7
d2["max"] = 12
print(d1) // ["other": 7, "min": 2, "max": 10]
print(d2) //["min": 2, "max": 12]
在swift
标准库中,为了提升性能,String、Array、Dictionary、Set
采取了Copy On Write
的技术
当我们要修改内存的时候,才会进行深度拷贝操作。
下面的代码中,当s2
没有做修改操作的时候,s1
和s2
是共用一块内存地址。
var s1 = "jack"
var s2 = s1
引用类型
引用类型赋值给var
let
或者给函数传参,是将内存地址拷贝一份。
类似于制作一个文件的替身(快捷方式、链接),指向的是同一个文件,属于浅拷贝shallow copy
class Size {
var width: Int
var height: Int
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
var s1 = Size(width: 10, height: 20)
var s2 = s1
//获得引用所指向内存的地址
print(Mems.ptr(ofRef: s1)) // 0x000000010043d510
print(Mems.ptr(ofRef: s2)) // 0x000000010043d510
// 修改了s1.width,同时s2.width的值也跟着变动
print(s2.width) // 10
s1.width = 100
print(s2.width) // 100
引用类型的赋值操作
class Size {
var width: Int
var height: Int
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
var s1 = Size(width: 10, height: 20)
s1 = Size(width: 20, height: 30)
var s1 = Size(width: 10, height: 20)
指向了堆空间的Size
对象
s1 = Size(width: 20, height: 30)
又重新指向了一个全新的Size
对象
值类型、引用类型的let
来看一个结构体跟一个类的let
常量初始化
struct Point {
var x: Int
var y: Int
}
let p = Point(x: 10, y: 20)
p = Point(x: 20, y: 30) //报错:Cannot assign to value: 'p' is a 'let' constant
p.x = 33 //报错:Cannot assign to property: 'p' is a 'let' constant
p.y = 44 //报错:Cannot assign to property: 'p' is a 'let' constant
值类型Point
的常量p
不允许重新指向其他对象,其内部的成员虽然是变量var
类型,同样也不允许重新赋值
class Size {
var width: Int
var height: Int
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
let s = Size(width: 10, height: 20)
s = Size(width: 20, height: 30) //报错:Cannot assign to value: 's' is a 'let' constant
s.width = 33 //编译通过
s.height = 44 //编译通过
引用类型Size
的常量s
不允许重新指向其他对象,但是其内部的成员是var
变量类型,允许重新赋值修改
1、let
代表p
、s
是常量,内存都不允许修改。
2、p
是结构体-值类型,它内存里面包含10
、20
两个值,内存大小16
个字节,同时内存不能改,所以这16
个字节都不能改,所以修改了x
、y
都会报错。
3、s
是类-引用类型,由于是常量,所以s
的内存不可以改,但是s
是引用类型,s
是一个指针变量,s
的内存只占8
个字节,代表着这8
个字节不可以修改,相当于存放堆空间Size
对象的地址值而已。然而s.width = 33
和s.height = 44
修改的并不是s
的内存,s
依然指向自己的对象。
let str = "jack"
str.append("_Fuck") //报错:Cannot use mutating member on immutable value: 'str' is a 'let' constant
let arr = [1, 2, 3]
arr[0] = 11 //报错:Cannot assign through subscript: 'arr' is a 'let' constant
arr.append(4) //报错:Cannot use mutating member on immutable value: 'arr' is a 'let' constant