美文网首页swift基础知识
Swift初学 - 四大自定义数据类型之Struct

Swift初学 - 四大自定义数据类型之Struct

作者: Joshua666 | 来源:发表于2019-10-10 14:11 被阅读0次

    Swift有四种自定义数据类型:structures, classes, enumerations和protocols。今天来详细介绍一下Struct,我们平时用的Int, String, Array, Dictionary等也都是以struct的形式定义的

    //From Swift Library
    public struct Int : FixedWidthInteger, SignedInteger {
     // …
    }
    

    一、Structure的声明与instance创建

    1、声明

    假设我们要为公司做一个员工统计:

    struct Person {
      let firstName: String
      let lastName: String
    }
    

    这里我们声明了一个Struct “Person”,每个person都有名字和姓,因为人的名字一般不会改,所以firstName和lastName都用了let(声明为constant)。公司的员工除了姓名外,至少还应该有个职称

    struct Employee {
      let identity: Person
      var jobTitle: String
      var salary: Double
    }
    

    这里identity的type是我们刚定义的Person,职称和薪资因为有可能会变,jobTitle、salary用var来声明。

    2、创建instance

    如果要创建一个Person的instance,我们可以用swift为struct自动生成的initializer

    let me = Person(firstName: "Joshua", lastName: "Jiang")
    

    值得注意的是,如果你要用这个自动生成的initializer,必须要在创建instance的时候把所有properties都赋值才行,即使你在声明的时候给了默认值(除非这个属性的类型是optional)。如果我们想创建一个Employee就可以写成

    var joshua = Employee(identity: me, jobTitle: "CTO", salary: 3000)
    

    注意因为职称可能会变,如果我们用let声明了joshua,以后他变ceo的时候,即使jobTitle是变量,修改它也会出error

    let joshua = Employee(identity: me, jobTitle: "CTO", salary: 3000)
    joshua.jobTitle = "CEO" //Error: cannot assign to property
    

    二、Properties属性

    1、stored properties和computed properties

    我们刚刚定义的Person和Employee下的firstName、lastName、jobTitle等都属于stored property,他们都储存了我们赋给他们的值,是占用内存空间的;但是还有一种computed properties是随时用随时计算出来的,并不占用任何内存空间,没有值被储存。举个例子:

    struct Employee {
      let identity: Person
      var jobTitle: String
      var salary: Double
    
      var tax: Double {
        return salary * 0.05
      }
    }
    

    我们在Employee类型里加了一个新的变量tax,代表这个员工需要交的税。如果税只需要工资就能计算出来,那么如果我们把tax声明成一个stored property,然后每次创建一个Employee的时候还需要先人工计算出他的tax再赋值,那就太傻了;这个时候computed property最适合。注意computed property必须是用var来声明。

    var joshua = Employee(identity: me, jobTitle: "CTO", salary: 3000)
    let tax = joshua.tax //150.0
    

    上述例子中的tax是一个只读computed property,有需要的话我们也可以定义成可读可写的

    var tax: Double {
      get {
        return salary * 0.05
      }
      set {
        salary = newValue / 0.05
      }
    }
    

    因为我们想让tax变成可读可写,那就需要自定义get和set这两个方法(如果是只读,swift会自动帮我们加上get)。这样的话,如果我们给tax赋值,salary就会相应的改变(在现实生活中可能没什么意义)。newValue是自动传入的参数,代表tax新被赋予的值。

    joshua.tax = 300
    print(joshua.salary) //6000.0
    

    2、type properties

    computed property和stored property都是instance的属性,数据类型也有自己的属性,这就是type property。比如:

    struct Employee {
      static var location = "青岛"
      let identity: Person
      var jobTitle: String
      var salary: Double
    }
    

    location前面加了static,这就意味着location是Employee这个类型的属性,不用创建instance就可以读取。在实践中有时候会很有用。

    let location = joshua.location //Error: you can't access a type property on an instance
    let location = Employee.location //正确用法
    

    3、property observers

    store property是有observer观察者的,willSet会在属性即将更新的时候执行;didSet会在属性刚更新完的时候执行。假设薪水突然翻番儿了,那就是location变了(现实逻辑瞎扯,看懂代码逻辑就行)

    var salary: Double {
      didSet {
        if salary >= oldValue * 2 {
          Employee.location = "北京"
        }
      }
    }
    

    a) didSet中,salary已经是更新之后的值了
    b) 改变之前的值可以用oldValue来读取更新之前的值
    c) 为了区别于其他属性,你需要用Employee.location来说明location是type property
    d) didSet和willSet只能用于stored property,你想监听computed property的话,直接在他们的set里实现相应逻辑就行了
    e) 在创建Employee instance的时候,didSet和willSet并不会执行,只有更新的时候才会
    f) 读完e),也就说明只有var声明的变量才可以用didSet和willSet

    三、Struct中的methods

    1、定义

    首先如果一个func定义在struct的外面,那他就是个function,如果定义在struct的里面那他就是method。但因为我们已经有了computed property, 我们在需要大量计算或者需要读写数据库的时候用methods,其他情况一般用computed property就可以了。

    let jobTitles = ["Developer", "CTO", "COO", "CFO", "CEO"]
    
    struct Employee {
      let identity: Person
      var jobTitle: String
      var salary: Double
    
      func roomFor() -> String {
            guard let index = jobTitles.firstIndex(of: self.jobTitle) else {
                return "Unknow"
            }
            return "00\(index)"
        }
    }
    

    我们定义了一个method来获取员工的房间号码,这个很简单,一个小地方说明一下,因为roomFor是在struct内部定义的method,self完全可以省略。

    var joshua = Employee(identity: me, jobTitle: "CTO", salary: 3000)
    joshua.roomFor() // "000"
    

    2、自定义init()

    我们之前创建instance的时候用的都是系统生成的init,但我们公司现在只缺月薪2000的程序员了,创建的时候每次输入同样的值太麻烦。这时候我们就可以自定义init()。

    struct Employee {
      let identity: Person
      var jobTitle: String
      var salary: Double
    
      init(identity: Person) {
        self.identity = identity
        jobTitle = "Developer"
        salary = Double(2000.0)
      }
    }
    
    var joshua = Employee(identity: me) //简单多了
    

    a) 有了自定义的init,之前自动生成那个就不能用了哦,需要的话再自己写一个
    b) 这里的self是需要的,因为要区别于local variable

    3、mutating methods

    struct里的method是不能改变属性的值的,除非定义的时候在前面加mutating

    mutating func raise() {
      salary += 100
    }
    

    a) 我们知道swift中,function一般是不能改变传入参数的值的,除非传入参数被标明inout;有了mutating,swift会帮我们偷偷把self标明inout的
    b) 如果一个instance想要执行raise,那他一定要是一个var声明的变量

    4、type methods

    和type property一样,类型可以有自己的type method,比如

    let jobTitles = ["CTO", "COO", "CFO", "CEO"]
    
    struct Employee {
        let identity: Person
        var jobTitle: String
        var salary: Double
        
        static func salaryOf(jobTitle: String) -> Double {
            guard let index = jobTitles.firstIndex(of: jobTitle) else {
                return 0.0
            }
            return Double(3000) * Double(index + 1)
        }
    }
    
    Employee.salaryOf(jobTitle: "CEO") //12000
    

    四、Extension

    假设Employee是个第三方库,我们不能改源码,这时候就可以通过extension来填加自定义method:

    extension Employee {
      init(identity: Person) {
        self.identity = identity
        jobTitle = "Developer"
        salary = Double(2000.0)
      }
    }
    

    我们用extension加了一个自定义init,跟之前在struct里面加的区别是,用extension可以保留系统自动生成的那个init。

    需要注意的是:
    a) extension不能用来加store property,因为这样会更改已有struct内存占用大小,破坏已有代码。
    b) extension不能override原struct已有的method

    相关文章

      网友评论

        本文标题:Swift初学 - 四大自定义数据类型之Struct

        本文链接:https://www.haomeiwen.com/subject/ukenpctx.html