## Swift 下標和運算符重載
在Swift的基礎類型中,比如數組、字典。我們通過`arr[0]`、`dict["name"]`等,在方括號中傳入的參數就是下標。
在Swift語言中,我們不僅僅可以使用系統自帶的下標來索引數組、字典中的元素,我們還可以為自己所創建的任何類型,例如:枚舉、結構體或者類來定義下標。
以結構體為例,使用 `subscript` 關鍵字申明。如下:
```
struct Vector{
var x: Double = 0.0
var y: Double = 0.0
var z: Double = 0.0
// 下標:接受參數為整型,返回浮點型
subscript(index: Int) -> Double? {
get { // 調用下標的邏輯
switch index{
case 0: return x
case 1: return y
case 2: return z
default: return nil
}
}
set { // 設置下標的邏輯
guard let newValue = newValue else{
return
}
switch index{
case 0: x = newValue
case 1: y = newValue
case 2: z = newValue
default: return
}
}
}
subscript (axis: String) -> Double? {
// 不寫 默認是 getter
switch axis {
case "x","X" : return x
case "y","Y": return y
case "z","Z": return z
default: return nil
}
}
}
var v = Vector(x: 1.1, y: 2.2 , z: 3.3)
v.y // 2.2
v[2] // 3.3
v["x"] // 1.1
v["T"] // nil
// 使用下標對結構體屬性賦值
v[1] = 9.09
v.y // 9.09
```
> 在一個結構體、枚舉或者類中,我們可以根據需要寫多個下標的定義。
### 多維下標
```
// 矩陣
struct Matrix {
var data: [[Double]]
var r: Int
var c: Int
init(row: Int, col:Int) {
self.r = row
self.c = col
data = [[Double]]()
for _ in 0..<r {
let aRow = Array(repeating: 0.0, count: col)
data.append(aRow)
}
}
subscript(x: Int, y:Int) -> Double {
get {
assert(x >= 0 && x < self.r && y >= 0 && y < self.c, "Index out of range") // 斷言
return data[x][y]
}
set {
assert(x >= 0 && x < self.r && y >= 0 && y < self.c, "Index out of range") // 斷言
data[x][y] = newValue
}
}
subscript(row: Int) -> [Double] {
get {
assert(row >= 0 && row < self.r, "Index out of range.") // 斷言
return data[row]
}
set(vector) {
assert(vector.count == self.c, "column number does not match.") // 斷言
data[row] = vector
}
}
}
var m = Matrix(row: 2, col: 2)
m[1, 1]
m[1, 1] = 100.0
m[1]
m[1][1]
m[0] = [1.5, 4.5]
m[0][1]
m[0, 0]
print(m)
```
### 運算符重載
假如有如下自定義結構體為例,進行運算符的重載。
```
struct Vector {
var x: Double = 0.0
var y: Double = 0.0
var z: Double = 0.0
// 下標
subscript(index: Int) -> Double? {
get{
switch index{
case 0: return x
case 1: return y
case 2: return z
default: return nil
}
}
set{
guard let newValue = newValue else{
return
}
switch index{
case 0: x = newValue
case 1: y = newValue
case 2: z = newValue
default: return
}
}
}
}
var va = Vector(x: 1.0, y: 2.0, z: 3.0)
var vb = Vector(x: 3.0, y: 4.0, z: 5.0)
// 定義函數重載 + 運算符
func +(left: Vector, right: Vector) -> Vector {
return Vector(x: left.x + right.x, y: left.y + right.y, z: left.z + right.z)
}
va + vb
// 定義函數重載 - 運算符
func - (left: Vector, right: Vector) -> Vector{
return Vector(x: left.x - right.x, y: left.y - right.y, z: left.z - right.z)
}
vb - va // Vector(x: 2.0, y: 2.0, z: 2.0)
// 定義函數重載 * 運算符
func * (left: Vector, right: Vector) -> Double {
return left.x * right.x + left.x * right.y + left.z * right.z
}
va * vb // 22.0
// 定義函數重載 * 運算符
func * (left: Vector, a: Double) -> Vector {
return Vector(x: left.x * a, y: left.y * a, z: left.z * a)
}
va * -1.0 // Vector(x: -1.0, y: -2.0, z: -3.0)
// 這次運算符接收的參數是不一樣的,所以和上面的運算符沒有影響.
// 復用重載的 * 運算符
func * (a: Double , right: Vector) -> Vector {
return right * a // 由于上面寫了向量 * 浮點數,這里可以復用上面的 * 運算符
}
-2.0 * va
// 定義函數重載 += 運算符
func +=( left: inout Vector , right: Vector) { // 左側的值需要返回值,所以定義一個inout參數,所以也不需要定義函數的返回值
left = left + right
}
va += vb
va // Vector(x: 4.0, y: 6.0, z: 8.0)
// 定義函數重載 -= 運算符
func -= (left: inout Vector, right: Vector){
left = left - right
}
vb -= va
```
> 對于運算符的重載,我們是不可以重載 = 運算符的,或者將 = 不當做運算符號。
#### 重載運算符 - 表示對值取反
```
使用 `prefix` 關鍵字,標識該運算符當做運算的前綴來使用。
prefix func - (vector: Vector) -> Vector{
return Vector(x: -vector.x, y: -vector.y, z: -vector.z)
}
-va // Vector(x: -4.0, y: -6.0, z: -8.0)
```
#### 重載邏輯運算符
```
struct Vector {
var x: Double = 0.0
var y: Double = 0.0
var z: Double = 0.0
// 下標
subscript(index: Int) -> Double? {
get{
switch index{
case 0: return x
case 1: return y
case 2: return z
default: return nil
}
}
set{
guard let newValue = newValue else{
return
}
switch index{
case 0: x = newValue
case 1: y = newValue
case 2: z = newValue
default: return
}
}
}
}
var va = Vector(x: 1.0, y: 2.0, z: 3.0)
var vb = Vector(x: 3.0, y: 4.0, z: 5.0)
// 重載 == 比較運算符
func == (left: Vector, right: Vector) -> Bool {
return left.x == right.x && left.x == right.y && left.z == right.z
}
va == vb // false
// 重載 == 比較運算符
func != (left: Vector, right: Vector) -> Bool{
// return left.x != right.x || left.y != right.y || left.z != right.z
return !(left == right) // 復用上面重載的 == 運算符的結果,邏輯取反
}
va != vb // true
// 重載 < 比較運算符
func < (left: Vector, right: Vector) -> Bool {
if left.x != right.x {return left.x < right.x}
if left.y != right.y {return left.y < right.y}
if left.z != right.z {return left.z < right.z}
return false
}
// 重載 <= 比較運算符
func <= (left: Vector, right: Vector) -> Bool {
return left < right || left == right
}
// 重載 > 比較運算符
func > (left: Vector, right: Vector)-> Bool{
return !(left <= right)
}
// 重載 >= 比較運算符
func >= (left: Vector, right: Vector) -> Bool{
return !(left > right)
}
```
> 對于比較運算符而言,返回值是Bool類型。
### 自定義運算符
#### 定義單目運算符
Custom operators can begin with one of the ASCII characters `/`, `=` , `-` , `+` , `!` , `*` , `%` , `<` , `>` , `&` , `|` , `^` , or `~` , or with one of the Unicode characters
```
struct Vector{
var x: Double = 0.0
var y: Double = 0.0
var z: Double = 0.0
// 下標
subscript(index: Int) -> Double? {
get{
switch index{
case 0: return x
case 1: return y
case 2: return z
default: return nil
}
}
set{
guard let newValue = newValue else{
return
}
switch index{
case 0: x = newValue
case 1: y = newValue
case 2: z = newValue
default: return
}
}
}
}
var va = Vector(x: 1.0, y: 2.0, z: 3.0)
var vb = Vector(x: 3.0, y: 4.0, z: 5.0)
// 重載 + 運算符
func + (left: Vector , right: Vector) -> Vector{
return Vector(x: left.x+right.x, y: left.y+right.y
, z: left.z+right.z)
}
// 重載 += 運算符
func += ( left: inout Vector , right: Vector) {
left = left + right
}
// 后置 +++ 運算符
postfix operator +++ {} // 聲明一個 swift 不存在的運算符
postfix func +++(vector: inout Vector) -> Vector {
vector += Vector(x: 1.0, y: 1.0, z: 1.0)
return vector
}
print(va+++) // Vector(x: 2.0, y: 3.0, z: 4.0)
// 前置 +++ 運算符
prefix operator +++ {} // 聲明一個 swift 不存在的運算符
prefix func +++(vector: inout Vector) -> Vector {
let ret = vector
vector += Vector(x: 1.0, y: 1.0, z: 1.0)
return ret
}
+++va
print(va) // Vector(x: 3.0, y: 4.0, z: 5.0)
```
#### 定義雙目運算符
```
struct Vector{
var x: Double = 0.0
var y: Double = 0.0
var z: Double = 0.0
// 下標
subscript(index: Int) -> Double? {
get{
switch index{
case 0: return x
case 1: return y
case 2: return z
default: return nil
}
}
set{
guard let newValue = newValue else{
return
}
switch index{
case 0: x = newValue
case 1: y = newValue
case 2: z = newValue
default: return
}
}
}
func length() -> Double {
return sqrt( self.x * self.x + self.y * self.y + self.z * self.z )
}
}
var va = Vector(x: 1.0, y: 2.0, z: 3.0)
var vb = Vector(x: 3.0, y: 4.0, z: 5.0)
func * (left: Vector, right: Vector) -> Double {
return left.x * right.x + left.x * right.y + left.z * right.z
}
```
> 使用 `infix` 關鍵字定義雙目運算符。
##### 自定義 ^ 運算符
```
infix operator ^ {}
func ^(left: Vector, right: Vector) -> Double{
return cos( (left * right) / (left.length() * right.length()) )
}
va ^ vb
```
##### 自定義 ** 運算符求冪運算
```
infix operator ** : ATPrecedence
precedencegroup ATPrecedence {
associativity: left
higherThan: AdditionPrecedence
lowerThan: MultiplicationPrecedence
}
func ** (x: Double, p: Double)-> Double{
return pow(x,p)
}
2**3**3 // 521
1+2**3**3 // 522
5*2**3**2 // 1000000
```
> Apple 的一些運算符信息參考這里: https://developer.apple.com/reference/swift/1851035-swift_standard_library_operators#//apple_ref/doc/uid/TP40016054
- 學習筆記
- 基礎
- 基本類型之整型
- 基本類型之浮點型
- 基本類型之布爾類型以及簡單的 if 語句
- 基礎類型之元組
- 基本類型之其他
- 運算符
- 基礎運算符
- 比較運算符、邏輯運算符
- 三元運算符
- 范圍運算符for-in
- 邏輯控制
- 循環結構
- 選擇結構
- 字符串
- Character和Unicode
- String.index 和 range
- 可選型
- 容器類
- 數組初始化
- 數組基本操作
- 字典初始化
- 字典基本操作
- 集合初始化
- 集合基本操作
- 函數
- 閉包
- 枚舉
- 結構體
- 類
- 文檔注釋
- 屬性和方法
- 下標和運算符重載
- 拓展和泛型
- 協議
- 其他
- Swift 3.0 For 循環
- Swift 隨機數的生成
- IOS開發玩轉界面 UIKit
- UILable 文本顯示控件
- UIButton 簡單的交互控件
- UIImageView 圖片控件
- UISearchBar 搜索控件