文章摘要
GPT 4
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结

结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Album{
let title:String
let artist:String
let year:Int

func printSummary(){
print("\(title) (\(year)) by \(artist)")
}
}

let album = Album(title: "呼吸之野", artist: "许嵩", year: 2022)
album.printSummary()
//输出 呼吸之野 (2022) by 许嵩

要注意的是这里的结构体跟Java的类有区别,是值类型。

1
2
3
4
5
6
7
8
9
//省略结构体 跟上面一样
var album = Album(title: "素颜", artist: "许嵩", year: 2010)
var album2 = album
album2.addArtist(name: "何曼婷")
album.printSummary()
album2.printSummary()
//输出
//素颜 (2010) by 许嵩
//素颜 (2010) by 许嵩 & 何曼婷

当结构体被赋值给新的变量、作为参数传递给函数或方法,或者从函数或方法返回时,会进行值拷贝,即创建一个完全独立的副本。

可变方法修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Album{
let title:String
var artist:String
let year:Int

func printSummary(){
print("\(title) (\(year)) by \(artist)")
}

mutating func addArtist(name : String){
artist = "\(artist) & \(name)"
}
}

var album = Album(title: "素颜", artist: "许嵩", year: 2010)
album.addArtist(name:"何曼婷")
album.printSummary()
//输出 素颜 (2010) by 许嵩 & 何曼婷

在结构体方法中,如果要修改结构体自身的属性,必须使用 mutating 关键字。因为结构体是值类型,默认情况下方法不能修改属性的值。

计算属性

1
2
3
4
5
6
7
8
struct Rectangle {
let width: Double
let height: Double

var area: Double {
return width * height
}
}

计算属性不会实际存储数据,而是在被访问时根据特定的逻辑计算并返回结果。

属性观察器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct Game{
var score = 0
}

var game = Game()
game.score += 10
print("Score is now \(game.score)")
game.score -= 3
print("Score is now \(game.score)")
game.score += 1
print("Score is now \(game.score)")
//输出
//Score is now 10
//Score is now 7
//Score is now 8

//借助属性观察器能实现相同的效果
struct Game{
var score = 0{
willSet{
print("Current Score is \(score)")
print("New value is now \(newValue)")
}
didSet{
print("Score is now \(score)")
print("Old value is \(oldValue)")
}
}
}

var game = Game()
game.score += 10
game.score -= 3
game.score += 1

比如我们想在每次score值变动时打印新值,可以借用关键词 willSetdidSet ,可以分别打印变动前和变动后的值,还有 newValueoldValue 属性,可以在对应方法里拿到改动前后的值。

初始化

1
2
3
4
5
6
7
8
9
10
11
struct Player{
let name : String
let number : Int
init(name: String){
self.name = name
number = Int.random(in: 1...99)
}
}

var player = Player(name:"yikun")
print(player.number)

init 关键字,这个初始化类似在java的构造器中做的一些赋值, self 就好比Java构造器的 this 属性名和参数重复时加上来区别,而且必须初始化所有属性,不然构建不成功。

访问控制

  • private 只能在该类型的定义内部被访问
  • fileprivate 可以在定义它的整个源文件内被访问,但在其他源文件中不可见
  • public 可以在任何地方被访问

大部分语言都有的访问控制,没啥说的

静态属性

static 没啥区别,该属性属于类型本身,而不是类型的实例,所有的实例共享同一个静态属性的值;非静态可以访问静态,静态不可以访问非静态。

总结

  • 您可以使用 struct 关键字创建自己的结构体。
  • 结构体可以拥有自己的属性和方法,如果方法修改了其结构的属性,则它必须是可变的。
  • 结构体可以具有存储属性和计算属性,我们可以将 didSetwillSet 属性观察器附加到属性上。
  • Swift 使用其属性名称为所有结构体生成一个初始化程序。
  • 您可以创建自定义初始化程序来覆盖 Swift 的默认值。
  • 访问控制限制了哪些代码可以使用属性和方法。
  • 静态属性和方法直接附加到结构体。

课后作业

创建一个结构来存储有关汽车的信息,包括:

  • 它的型号
  • 座位数
  • 当前档位
  • 添加一种调高或调低档位的方法。
  • 考虑变量和访问控制。
  • 不允许无效档位 -1…10 似乎是合理的最大范围。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct Car{
private let model : String
private let seatNum : Int
private var gear:Int{
didSet{
print("This \(model)'s gear is \(gear)")
}
}
init(model : String,seatNum : Int){
self.model = model
self.seatNum = seatNum
gear = 0
}
mutating func changeGears(gear : Int){
if gear>=0 && gear<=10 {self.gear = gear}
else{ print("不允许无效档位")}
}
}

var car = Car(model: "xiaomi su7", seatNum: 5)
car.changeGears(gear: 5)
car.changeGears(gear: 1)
car.changeGears(gear: -5)
car.changeGears(gear: 3)
//输出
//This xiaomi su7's gear is 5
//This xiaomi su7's gear is 1
//不允许无效档位
//This xiaomi su7's gear is 3