认识Swift系列10之下标(类、结构体、枚举皆可用)
2019-07-12 本文已影响0人
Niuszeng
// 下标subscript本质就是一个方法
// 使用下标定义了方法后,外部可以通过中括号[]方式方位setter和getter方法
// subscript方法的返回值类型决定了set的newValue类型和get方法的返回值类型
class Point {
var x = 0.0, y = 0.0, z = 0.0
subscript(index: Int) -> Double {
set {
if index == 0 {x = newValue}
else if index == 1 {y = newValue}
else {z = newValue}
}
get {
if index == 0 {return x}
else if index == 1 {return y}
else {return z}
}
}
subscript(index: String) -> Double {
set {
if index == "x" {x = newValue}
else if index == "y" {y = newValue}
else {z = newValue}
}
get {
if index == "x" {return x}
else if index == "y" {return y}
else {return z}
}
}
func show() {
print("x == \(x),y == \(y),z == \(z)")
}
}
let p = Point()
p.show()
p[0] = 20
p[1] = 1
p[2] = 9
p.show()
p["x"] = 33
p["y"] = 44
p["z"] = 55
p.show()
// subscript可以没有set方法,但是必须要有get方法,只有get的时候,可以省略get
// 必须有get,可以省略set
class Size {
var w = 0.0, h = 0.0
// 只有get
/**
subscript(index: Int) -> Double {
get {
if index == 0 {return w}
else {return h}
}
}
*/
// 只有get可以省略get
subscript(index: Int) -> Double {
if index == 0 {return w}
else {return h}
}
func show() {
print("w == \(w),h == \(h)")
}
}
// 可以设置参数标签
class Point1 {
var x = 0.0, y = 0.0, z = 0.0
subscript(indexTag index: Int) -> Double {
set {
if index == 0 {x = newValue}
else if index == 1 {y = newValue}
else {z = newValue}
}
get {
if index == 0 {return x}
else if index == 1 {return y}
else {return z}
}
}
func show() {
print("x == \(x),y == \(y),z == \(z)")
}
}
let p1 = Point1()
p1.show()
p1[indexTag: 0] = 23
p1[indexTag: 1] = 33
p1[indexTag: 2] = 43
p1.show()
// 下标可以传多个参数
// 下标可以使类方法
class Point2 {
static subscript(v1: Int, v2: Int) -> Int {
v1 + v2
}
}
print(Point2[1, 10])
// 下标返回结构体和类的区别
// 当结构体类添加下标方法的时候,有适合可能必须加入set方法
func testStruct() {
class File {
var x = 0, y = 0
}
class FileManager {
var f = File()
subscript(index: Int) ->File { f }
}
let fm = FileManager();
fm[0].x = 10
fm[0].y = 10
print("class fm f (\(fm.f.x), \(fm.f.y))")
}
func testClass() {
struct File {
var x = 0, y = 0
}
struct FileManager {
var f = File()
subscript(index: Int) ->File {
set {
f = newValue
// 虽然外部值修改f的x属性,但实际操作是外部会构建新的结构体来进行值覆盖
}
get {f}
}
}
var fm = FileManager();
fm[0].x = 10 // f = File(x: 10, y: fm[0].y)
fm[0].y = 10 // f = File(x: fm[0].x, y: 10)
// 两句代码虽然是对f成员的x和y赋值,但对于结构体来说实际上是内存中值得copy过程
// 即 f.x = 10 等价于 f = File(x:10 y:f.y)
// 因此,fm[0].x = 10实际上需要调用下标方法中的set方法
// 所以,下标方法必须实现set
print("class fm f (\(fm.f.x), \(fm.f.y))")
}
testStruct()
testClass()
// 接收多个参数的下标
class Grid {
static let NotFound = -1
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 Grid.NotFound }
return data[row][column]
}
}
}
var g = Grid()
g[0, 0] = 40
g[1, 1] = 40
g[2, 2] = 40
print(g.data)