Swift基础-结构、属性和方法

创建自己的结构

Swift可让您通过两种方式设计自己的类型,其中最常见的称为结构,或简称为structs。可以给结构赋予它们自己的变量和常量以及它们自己的功能,然后根据需要创建和使用它们。

让我们从一个简单的示例开始:我们将创建一个Sport将其名称存储为字符串的结构。结构内部的变量称为properties,因此这是具有一个属性的结构:

struct Sport {
    var name: String
}

定义了类型,因此现在我们可以创建和使用它的实例:

var tennis = Sport(name: "Tennis")
print(tennis.name)

我们制作了nametennis变量,因此可以像常规变量一样更改它们:

tennis.name = "Lawn tennis"

属性可以像常规变量一样具有默认值,并且通常可以依靠Swift的类型推断。

计算属性

我们只是创建了一个Sport这样的结构:

struct Sport {
    var name: String
}

具有存储一个String的属性name。这些称为存储属性,因为Swift具有另一种称为计算属性的属性-一种运行代码以计算其值的属性。

我们将向该Sport结构添加另一个存储的属性,然后是一个计算的属性。看起来是这样的:

struct Sport {
    var name: String
    var isOlympicSport: Bool

    var olympicStatus: String {
        if isOlympicSport {
            return "\(name) is an Olympic sport"
        } else {
            return "\(name) is not an Olympic sport"
        }
    }
}

如您所见,它olympicStatus看起来像一个普通的String,但是它会根据其他属性返回不同的值。

我们可以通过创建一个新实例Sport来进行尝试:

let chessBoxing = Sport(name: "Chessboxing", isOlympicSport: false)
print(chessBoxing.olympicStatus)

let gameBoxing = Sport(name: "gameBoxing", isOlympicSport: true)
print(gameBoxing.olympicStatus)

输出内容如下:

Chessboxing is not an Olympic sport
gameBoxing is an Olympic sport

属性观察器

通过属性观察器,可以在任何属性更改之前或之后运行代码。为了说明这一点,我们将编写一个Progress跟踪任务和完成百分比的结构:

struct Progress {
    var task: String
    var amount: Int
}

现在,我们可以创建该结构的实例并随时间调整其进度:

var progress = Progress(task: "Loading data", amount: 0)
progress.amount = 30
progress.amount = 80
progress.amount = 100

我们想让 Swift每次amount更改时都打印一条消息,我们可以使用didSet属性观察器。每次amount更改时,它将运行一些代码:

struct Progress {
    var task: String
    var amount: Int {
        didSet {
            print("\(task) is now \(amount)% complete")
        }
    }
}

您还可以willSet用来在属性更改之前采取措施,但这很少使用。

方法

结构内部可以具有函数,并且这些函数可以根据需要使用结构的属性。结构内部的函数称为方法,但它们仍使用相同的func关键字。

我们可以用一个City结构来证明这一点。这将具有一个population存储城市人口的属性,以及一个collectTaxes()返回人口乘以1000的方法。由于该方法属于City,因此可以读取当前城市的population属性。

这是代码:

struct City {
    var population: Int

    func collectTaxes() -> Int {
        return population * 1000
    }
}

该方法属于该结构,因此我们在该结构的实例上调用它,如下所示:

let london = City(population: 9_000_000)
london.collectTaxes()

变异方法

如果一个结构具有可变属性,但是该结构的实例被创建为常量,则该属性不能更改–该结构是恒定的,因此,无论如何创建,其所有属性也是恒定的。

问题在于,当您创建结构时,Swift不知道是否将其与常量或变量一起使用,因此默认情况下采用安全方法:除非明确要求,否则Swift不会允许您编写更改属性的方法。

当您想在方法内部更改属性时,需要使用mutating关键字对其进行标记,如下所示:

struct Person {
    var name: String

    mutating func makeAnonymous() {
        name = "Anonymous"
    }
}

因为它更改了属性,所以Swift仅允许在Person作为变量的实例上调用该方法:

var person = Person(name: "Ed")
person.makeAnonymous()

字符串的属性和方法

到目前为止,我们已经使用了很多字符串,事实证明它们是结构-它们具有自己的方法和属性,可用于查询和操作字符串。

首先,让我们创建一个测试字符串:

let string = "Do or do not, there is no try."

您可以使用其count属性读取字符串中的字符数:

print(string.count)

他们有一个hasPrefix()方法,如果字符串以特定字母开头,则返回true

print(string.hasPrefix("Do"))

您可以通过调用字符串的uppercased()方法将其大写:

print(string.uppercased())

您甚至可以让Swift将字符串的字母排序成一个数组:

print(string.sorted())

字符串具有更多的属性和方法-尝试键入string.以显示Xcode的代码完成选项。

数组的属性和方法

数组也是结构,这意味着它们也具有自己的方法和属性,可用于查询和操作数组。

这是一个让我们开始的简单数组:

var toys = ["Woody"]

您可以使用其count属性读取数组中的项目数:

print(toys.count)

如果要添加新项目,请使用如下append()方法:

toys.append("Buzz")

您可以使用其firstIndex()方法在数组内找到任何项,如下所示:

toys.firstIndex(of: "Buzz")

这将返回1,因为数组从0开始计数。

就像使用字符串一样,您可以让Swift将数组的项目按字母顺序排序:

print(toys.sorted())

最后,如果要删除项目,请使用如下remove()方法:

toys.remove(at: 0)

数组具有更多的属性和方法–尝试键入toys.以显示Xcode的代码完成选项。

初始化器

初始化器是特殊的方法,提供不同的方法来创建结构。默认情况下,所有结构都带有一个名为成员级初始值设定项的值,这要求您在创建结构时为每个属性提供一个值。

如果我们创建User具有一个属性的结构,则可以看到以下内容:

struct User {
    var username: String
}

创建这些结构之一时,必须提供用户名:

var user = User(username: "twostraws")

我们可以提供自己的初始化程序来替换默认的初始化程序。例如,我们可能希望将所有新用户创建为“匿名”并打印一条消息,如下所示:

struct User {
    var username: String

    init() {
        username = "Anonymous"
        print("Creating a new user!")
    }
}

你不写func初始化之前,但是你做的必要,以确保所有属性都初始化结束前的值。

现在我们的初始化程序不接受任何参数,我们需要创建如下结构:

var user = User()
user.username = "twostraws"

引用当前实例

在方法内部,您会得到一个称为的特殊常量self,该常量指向当前正在使用的结构的任何实例。当您创建与属性具有相同参数名的初始值设定项时,此self值特别有用。。

例如,如果您创建一个Person带有name属性的结构,然后尝试编写一个接受name参数的初始化程序,则self可以帮助您区分属性和参数– self.name引用属性,而name引用参数。

这就是代码中的内容:

struct Person {
    var name: String

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

惰性属性

作为性能优化,Swift使您仅在需要时才创建一些属性。举个例子,考虑一下这个FamilyTree结构-它并没有做很多,但是从理论上讲,为某人创建家谱需要很长时间:

struct FamilyTree {
    init() {
        print("Creating family tree!")
    }
}

我们可以将该FamilyTree结构用作Person结构内部的属性,如下所示:

struct Person {
    var name: String
    var familyTree = FamilyTree()

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

var ed = Person(name: "Ed")

但是,如果我们不总是需要特定人的家谱怎么办?如果将lazy关键字添加到familyTree属性,则Swift仅在FamilyTree首次访问该结构时才会创建该结构:

lazy var familyTree = FamilyTree()

因此,如果您想看到“正在创建家谱!”消息,则需要至少访问一次该属性:

ed.familyTree

静态特性和方法

到目前为止,我们创建的所有属性和方法都属于struct的各个实例,这意味着,如果我们有一个Studentstruct,我们可以创建多个学生实例,每个实例都具有各自的属性和方法:

struct Student {
    var name: String

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

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

您也可以通过将Swift声明为static来要求Swift在该结构的所有实例之间共享特定的属性和方法。

为了尝试这一点,我们将向该Student结构添加一个静态属性,以存储该班级中有多少学生。每次创建新学生时,我们都会向其中添加一个:

struct Student {
    static var classSize = 0
    var name: String

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

因为该classSize结构属于该结构本身而不是该结构的实例,所以我们需要使用读取它Student.classSize

print(Student.classSize)

访问控制

访问控制允许您限制哪些代码可以使用属性和方法。这一点很重要,例如您可能希望阻止人们直接读取属性。

我们可以创建一个Person具有id属性以存储其社会保险号的结构:

struct Person {
    var id: String

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

let ed = Person(id: "12345")

创建该人后,我们可以将其id设为私有,因此您无法从结构外部读取它-尝试编写ed.id根本行不通。

只需使用private关键字,如下所示:

struct Person {
    private var id: String

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

现在,只有内部的方法Person可以读取id属性。例如:

struct Person {
    private var id: String

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

    func identify() -> String {
        return "My social security number is \(id)"
    }
}

另一个常见的选择是public,它允许所有其他代码使用属性或方法。

总结

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

你可能感兴趣的:(Swift基础-结构、属性和方法)