今天,你将学习结构的一些更高级的功能,这些功能使它们更强大,包括访问控制,静态属性和惰性。是的,懒惰 –比尔·盖茨曾经说过:“我选择一个懒惰的人来做艰苦的工作,因为一个懒惰的人会找到一种轻松的方法来完成它。”在Swift中,惰性是一项重要的性能优化。

初始化程序

初始化程序是为这个结构一个初始值。我们可以使用init方法来初始化程序,在之前不需要加func,但是必须要包含所有的参数:

1
2
3
4
5
6
7
8
9
10
11
12
struct Zhhoo {
var url: String
init(){
url = "zhhooo.com"
print("default: \(url)")
}
}


var adr = Zhhoo()
adr.url = "blog.zhhooo.com"

其他例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Country {
var name: String
var usesImperialMeasurements: Bool
init(countryName: String) {
name = countryName
let imperialCountries = ["Liberia", "Myanmar", "USA"]
if imperialCountries.contains(name) {
usesImperialMeasurements = true
} else {
usesImperialMeasurements = false
}
}
}

其他例子:

1
2
3
4
5
6
7
8
9
10
11
struct Cabinet {
var height: Double
var width: Double
var area: Double
init (itemHeight: Double, itemWidth: Double) {
height = itemHeight
width = itemWidth
area = height * width
}
}
let drawers = Cabinet(itemHeight: 1.4, itemWidth: 1.0)

引用当前实例(self)

在结构中,我们初始化的时候如果初始化的参数与结构中的参数名称相同时,为了区分,可以用self点记法来表示不同的位置。self指的是这个结构,而没有self指的是这个初始化方法。我们可以使用self

1
2
3
4
5
6
7
8
struct Person {
var name: String

init(name: String) {
print("\(name) was born!")
self.name = name
}
}

为了更好的表达出self具体指出的位置,我对代码进行了部分修改,用anamename区分:

1
2
3
4
5
6
7
8
9
10
struct Person {
var aname: String

init(name: String) {
print("\(name) was born!")
self.aname = name
}
}

var person = Person(name: "hello")

其他例子:

1
2
3
4
5
6
7
8
9
10
11
struct Language {
var nameEnglish: String
var nameLocal: String
var speakerCount: Int
init(english: String, local: String, speakerCount: Int) {
self.nameEnglish = english
self.nameLocal = local
self.speakerCount = speakerCount
}
}
let french = Language(english: "French", local: "français", speakerCount: 220_000_000)

其他例子:

1
2
3
4
5
6
7
8
struct Cottage {
var rooms: Int
var rating = 5
init(rooms: Int) {
self.rooms = rooms
}
}
let bailbrookHouse = Cottage(rooms: 4)

已经给定默认值后初始化可以不包含该参数。

惰性

我们可以将一个结构作为一个变量插入到另一个结构中,例如我们的第一个例子:

1
2
3
4
5
6
7
8
9
10
11
struct Zhhoo {
var url: String
init(){
url = "zhhooo.com"
print("default: \(url)")
}
}

struct Pop {
var name = Zhhoo()
}

这个时候直接用变量调用Pop结构会自动创建Zhhoo结构。有的时候我们做性能优化,创建的结构仅在第一次调用的时候创建。这个时候我们就用到了lazy

1
2
3
4
5
6
7
8
9
10
11
12
struct Zhhoo {
var url: String
init(){
url = "zhhooo.com"
print("default: \(url)")
}
}

struct Pop {
lazy var name = Zhhoo()

}

现在只有在调用name时才会创建Zhhoo结构:

1
2
var adr = Pop()
adr.name

结构的静态属性

在Swift中我们创建多个结构对应的变量时,我们通常(例:创建班级里的学生):

1
2
3
4
5
6
7
8
9
10
struct Student {
var name: String

init(name: String) {
self.name = name
}
}

let ed = Student(name: "Ed")
let taylor = Student(name: "Taylor")

有的时候我们需要结构中有一个不被任何变量/常量影响的变量(例:创建一个学生数量的变量,并在每创建一个学生后,学生总数增加1):

1
2
3
4
5
6
7
8
9
struct Student {
static var classSize = 0
var name: String

init(name: String) {
self.name = name
Student.classSize += 1
}
}

因为静态属性classSize不属于任何变量/常量,所以我们在调用的时候直接调用Student

1
print(Student.classSize)

在常规方法引入静态属性需要使用点记法:

1
2
3
4
5
6
7
8
9
10
struct Person {
static var population = 0
var name: String
init(personName: String) {
name = personName
//
Person.population += 1
//
}
}

访问控制

访问控制可以限制使用代码,你可能希望阻止别人阅读某个属性。例如:

1
2
3
4
5
6
7
8
9
struct Zhhoo {
var url: String
init(url: String) {
self.url = url
}
}

let website = Zhhoo(url: "zhhooo.com")
print(website.url)

这是一段正常的代码,如果我们要阻止结构外部访问website.url,我们可以将该属性设置为private(相反的,允许外部调用设置为public),例如:

1
2
3
4
5
6
7
struct Zhhoo {
private var url: String

init(url: String) {
self.url = url
}
}

现在外部属性无法调用url,只有内部可以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Zhhoo {
private var url: String

init(url: String) {
self.url = url
}

func go(){
print("Let's go to the \(url)")
}

}

let website = Zhhoo(url: "zhhooo.com")
website.go()

使用private时必须自己创建一个初始化器,否则无法将参数带入到结构中。例如下面这段代码是正确的:

1
2
3
4
struct Contributor {
private var name = "Anonymous"
}
let paul = Contributor()

这段代码是错误的:

1
2
3
4
5
struct Contributor {
var age = 13
private var name = "Anonymous"
}
let paul = Contributor(age: 13)

应该为:

1
2
3
4
5
6
7
8
struct Contributor {
var age : Int
private var name = "Anonymous"
init(age: Int){
self.age = age
}
}
let paul = Contributor(age: 13)

其他例子:

1
2
3
4
5
6
7
8
9
10
11
struct Office {
private var passCode: String
var address: String
var employees: [String]
init(address: String, employees: [String]) {
self.address = address
self.employees = employees
self.passCode = "SEKRIT"
}
}
let monmouthStreet = Office(address: "30 Monmouth St", employees: ["Paul Hudson"])

其他例子:

1
2
3
4
5
6
7
8
9
struct School {
var staffNames: [String]
private var studentNames: [String]
init(staff: String...) {
self.staffNames = staff
self.studentNames = [String]()
}
}
let royalHigh = School(staff: "Mrs Hughes")

其他例子:

1
2
3
4
5
6
7
8
struct Pokemon {
static var numberCaught = 0
var name: String
static func catchPokemon() {
print("Caught!")
Pokemon.numberCaught += 1
}
}

总结

  • 你可以使用结构创建自己的类型,这些结构可以具有自己的属性和方法。
  • 你可以使用存储的属性或使用计算的属性即时计算值。
  • 如果要更改方法内的属性,则必须将其标记为mutating。
  • 初始化程序是创建结构的特殊方法。默认情况下,你将获得一个成员初始化器,但是如果创建自己的初始化器,则必须为所有属性赋予一个值。
  • 使用self常量来引用方法内部结构的当前实例。
  • 该lazy关键字告诉斯威夫特当第一次使用,他们只能创建属性。
  • 你可以使用static关键字在结构的所有实例之间共享属性和方法。
  • 访问控制使你可以限制可以使用属性和方法的代码。

参考资料

查看下一天的SwiftUI学习笔记

关于100days英文课程