Swift结构体,类,枚举

枚举

枚举的定义

    // 枚举的定义
    enum Season {case spring; case summer; case autumn; case winter}
    
    enum Season1 {
        case spring
        case summer
        case autumn
        case winter
    }
    
    enum Seaso2 { case spring, summer, autumn, winter }
    

枚举关联值

有时将枚举的成员值跟其他类型的值关联存储在一起,会非常有用

    //关联值
    enum Date {
        case digit(year: Int, month: Int, day: Int)
        case string(String)
    }
    
    var date = Date.digit(year: 2021, month: 01, day: 18);
    date = .string("20210120")
    
    switch date {
    case let .digit(year: a, month: b, day: c):
        print(a, "-", b, "-", c)
    case let .string(str):
        print(str)
    default:
        print("c")
    }
    
    switch date {
    case .digit(year: let a, month: 02, day: let c):
        print(a, "-", "01", "-", c)
    case .string("20210118"):
        print("20210118")
    case .string("20210119"):
        print("20210119")
    default:
        print("other");
    }

枚举原始值

枚举成员可以使用相同类型的默认值预先对应,这个默认值叫做:原始值。原始值不占用枚举类型的内存

如果枚举的原始值类型是Int、String,Swift会自动分配原始值

    //原始值
    enum Season3:String {
        case spring = "春天"
        case summer = "夏天"
        case autumn = "秋天"
        case winter = "冬天"
    }
    
    var season = Season3.winter;
    season = .autumn
    print(season) //autumn
    print(season.rawValue) //秋天
    print(Season3.spring.rawValue) //春天
    
    enum Season4 : Int { case spring, summer, autumn, winter }//默认0123
    enum Season5 : Int { case spring = 1, summer, autumn = 5, winter }//默认1256
    
    

递归枚举 indirect

递归枚举需要加上indirect 关键字

     //递归枚举
    indirect enum Count {
        case num(Int)
        case sum(Count, Count)
        case difference(Count, Count)
    }
    
    enum Count2 {
        case num(Int)
        indirect case sum(Count2, Count2)
        indirect case difference(Count2, Count2)
    }

占用内存

  1. 只有原始值的枚举,所占的内存一般都是1个字节
  2. 如果有附加值,那么枚举值所占的空间,就是附加值所需最大的空间+ 1个字节。只有一个枚举值情况下不需要+1
enum Password { 
  case number(Int, Int, Int, Int) 
  case other 
}
MemoryLayout.stride // 40, 分配占用的空间大小 
MemoryLayout.size // 33, 实际用到的空间大小 
MemoryLayout.alignment // 8, 对齐参数

var pwd = Password.number(9, 8, 6, 4) 
pwd = .other 
MemoryLayout.stride(ofValue: pwd) // 40
MemoryLayout.size(ofValue: pwd) // 33 
MemoryLayout.alignment(ofValue: pwd) // 8

结构体

结构体定义

    struct Date {
        var year: Int = 2021
        var month: Int
        var day: Int
  }
  var date = Date(year: 2019, month: 6, day: 23)
  //传入所有成员值,用以初始化所有成员(存储属性,Stored Property)

构造方法

所有的结构体都有一个编译器自动生成的初始化器(initializer,初始化方法、构造器、构造方法)

编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有成员都有初始值

一旦在定义结构体时自定义了初始化器,编译器就不会再帮它自动生成其他初始化器

内存结构

struct Point { 
    var x: Int = 0 
  var y: Int = 0 
  var origin: Bool = false 
} 
print(MemoryLayout.size) // 17 
print(MemoryLayout.stride) // 24 
print(MemoryLayout.alignment) // 8

类的定义

     class Student {
        var age: Int = 18
        var name: String = "xiaoming"
    }

类的初始化

类的定义和结构体类似,但编译器并没有为类自动生成可以传入成员值的初始化器

如果类的所有成员都在定义的时候指定了初始值,编译器会为类生成无参的初始化器

class Point { 
  var x: Int = 10 
  var y: Int = 20 
}
let p1 = Point()

struct 与 class对比

struct是值类型,class是引用类型。

值类型的变量直接包含它们的数据,对于值类型都有它们自己的数据副本,因此对一个变量操作不可能影响另一个变量。

引用类型的变量存储对他们的数据引用,因此后者称为对象,因此对一个变量操作可能影响另一个变量所引用的对象。

二者的本质区别:

struct是深拷贝,值拷贝,拷贝的是内容;为了提升性能,String、Array、Dictionary、Set采取了Copy On Write的技术。仅当有“写”操作时,才会真正执行拷贝操作。不需要修改的,尽量定义成let

class是浅拷贝,引用拷贝,拷贝的是指针。在Mac、iOS中的malloc函数分配的内存大小总是16的倍数。通过class_getInstanceSize可以得知:类的对象至少需要占用多少内存

class Point {
  var x = 11
  var test = true
  var y = 22
} 
var p = Point() 
class_getInstanceSize(type(of: p)) // 40 class_getInstanceSize(Point.self)

property的初始化不同:

class 在初始化时不能直接把 property 放在 默认的constructor 的参数里,而是需要自己创建一个带参数的constructor;

而struct可以,把属性放在默认的constructor 的参数里。

immutable变量:

swift的可变内容和不可变内容用var和let来甄别,如果初始为let的变量再去修改会发生编译错误。

struct遵循这一特性;class不存在这样的问题。

mutating function:

struct 和 class 的差別是 struct 的 function 要去改变 property 的值的时候要加上 mutating,而 class 不用。

继承:

struct不可以继承,class可以继承。

struct比class更轻量:struct分配在栈中,class分配在堆中。

枚举、结构体、类都可以定义方法

class Size { 
  var width = 10 
  var height = 10 
  func show() { 
    print("width=\(width), height=\(height)") 
  } 
} 
let s = Size() 
s.show() // width=10, height=10


struct Point { 
  var x = 10 
  var y = 10 
  func show() { 
    print("x=\(x), y=\(y)") 
  } 
}
let p = Point() 
p.show() // x=10, y=10


enum PokerFace : Character { 
  case spades = "♠", hearts = "♥", diamonds = "♦", clubs = "♣" 
  func show() { 
    print("face is \(rawValue)") 
  } 
}
let pf = PokerFace.hearts 
pf.show() // face is ♥

方法占用对象的内存么?

不占用

方法的本质就是函数

方法、函数都存放在代码段

下标

使用subscript可以给任意类型(枚举、结构体、类)增加下标功能,有些地方也翻译为:下标脚本

subscript的语法类似于实例方法、计算属性,本质就是方法(函数)

// subscript中定义的返回值类型决定了 get方法的返回值类型 pset方法中newValue的类型

//subscript可以接受多个参数,并且类型任意

class Point {
    var p = Point()
  var x = 0.0, y = 0.0
  subscript(index: Int) -> Double { 
    set { 
      if index == 0 { 
        x = newValue 
      } else if index == 1 { 
        y = newValue 
      } 
    } 
    get { 
      if index == 0 { 
        return x 
      } else if index == 1 { 
        return y 
      } 
      return 0 
    }
  }
}

p[0] = 11.1
p[1] = 22.2

print(p.x) // 11.1 
print(p.y) // 22.2 
print(p[0]) // 11.1 
print(p[1]) // 22.2

subscript可以没有set方法,但必须要有get方法

如果只有get方法,可以省略get

class Point {
    var x = 0.0, y = 0.0
  subscript(index: Int) -> Double { 
    get { 
      if index == 0 { 
        return x 
      } else if index == 1 { 
        return y 
      } 
      return 0
    }
  }
}


class Point {
  var x = 0.0, y = 0.0
  subscript(index: Int) -> Double { 
    if index == 0 { 
      return x 
    } else if index == 1 { 
      return y 
    } 
    return 0
  }
}

下标可以设置参数标签

class Point {
    var x = 0.0, y = 0.0 
  subscript(index i: Int) -> Double { 
    if i == 0 { 
      return x 
    } else if i == 1 { 
      return y 
    } 
    return 0
  }
}

var p = Point() 
p.y = 22.2 
print(p[index: 1]) // 22.2

下标可以是类型方法

class Sum { 
  static subscript(v1: Int, v2: Int) -> Int { 
    return v1 + v2 
  } 
} 

print(Sum[10, 20]) // 30

结构体、类作为返回值对比

class Point { 
    var x = 0, y = 0 
} 
class PointManager { 
  var point = Point() 
  subscript(index: Int) -> Point { 
    get { point } 
  }
}


struct Point { 
  var x = 0, y = 0 
} 
class PointManager { 
  var point = Point() 
  subscript(index: Int) -> Point { 
    set { point = newValue } 
    get { point } 
  }
}

接收多个参数的下标

class Grid {
  var data = [ 
    [0, 1, 2], 
    [3, 4, 5], 
    [6, 7, 8] 
  ] 
  subscript(row: Int, column: Int) -> Int { 
    set { 
      guard row >= 0 && row < 3 && column >= 0 && column < 3 else { 
        return 
      }
      data[row][column] = newValue
    } get { 
      guard row >= 0 && row < 3 && column >= 0 && column < 3 else { 
        return 0 
      } 
      return data[row][column]
    }
  }
}

var grid = Grid()

grid[0, 1] = 77
grid[1, 2] = 88
grid[2, 0] = 99
print(grid.data)

你可能感兴趣的:(Swift结构体,类,枚举)