iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
0
Software Development

Swift 菜鳥的30天系列 第 16

Day-16 Swift 語法(12) - Methods 方法

方法 (Method)

方法是與特定類型相關聯的函數。Class,Struct 和 Enum 都可以定義實例方法,他們封裝給特定類型實例特定的任務和功能。Class,Struct 和 Enum 也可以定義與類型本身相關連的類型方法。他們為這些實例提供功能性,利用通過提供訪問和修改實例屬性的方法,或是通過提供與實例目的相關的功能。

要寫一個實例方法,你需要把它放在對應 Class 的大括號 {} 裡面。實例方法默認可以訪問同類下所有其他實例方法和屬性,實例方法只能在它所屬類型的特定實例上調用,不能在沒有現有實例的情況下獨立調用它。

我們下方舉一個時間的加總範例:

class Clock {
    var minute = 0
    var hour = 0
    func minCount(by min:Int) {
        minute += min
    }
    func hrCount(by hr:Int) {
        hour += hr
    }    
    func minToHr() {
        if minute >= 60 {
            hour += minute / 60
            minute -= 60 * (minute / 60)
        }
    }
}

我們在上方簡單宣告了 minute 跟 hour 兩個變數,以及三個 func 。 minCount 與 hourCount 是可以讓使用自行輸入整數提供兩個變數的值,minToHr 則是能讓 minute 轉換成 hour 的函數。我們試著把它存到一個實例中並使用它:

let timeSet = Clock()
timeSet.minCount(by: 241) // minute = 241
timeSet.hrCount(by: 5) // hour = 5
timeSet.minToHr() // minute 轉換為 hour 

上面我們設置完的結果,現在總共有 241 分鐘,以及 5 小時,為了要轉換他的單位(分鐘轉小時),所以我們必須使用 minToHr() 這個函數。其中因為 241/60 = 4 ,所以我們的 hour 會加上 4 , minute 則是被減去 60 * 4 ,經由這樣換算我們單位正確的總時數。

https://ithelp.ithome.com.tw/upload/images/20180104/20107701BpT9XK7LEO.png

Self 屬性

每一個 Class 的實例都隱含一個叫做 self 的屬性,它與實例本身相等。你可以使用 self 屬性來在當前實例當中調用它自身的方法。我們使用上面的例子加上 self :

 func minCount(by min:Int) {
        self.minute += min
    }
    func hrCount(by hr:Int) {
        self.hour += hr
    }

事實上,你不需要經常在程式碼中寫上 self。如果你沒有顯式地寫出 self ,Swift 會在你於方法中使用已知屬性或者方法的時候假設你是調用了當前實例中的屬性或者方法。就像上面例子,你不需要加上 self , Swift 會假設你是用我們宣告的 minute 變數。

下面我們使用一個比較 X 大小的例子,來說明 self 的差別:

struct compare {
    var x = 10
    func check(x:Int) -> String {
       var  msg = ""
        if x > self.x {
            msg = "你的輸入的 x 比我們的變數 x 還大"
        } else {
            msg = "你的輸入的 x 比我們的變數 x 還小"
        }
        return msg
    }
}

它的執行結果如下:
https://ithelp.ithome.com.tw/upload/images/20180104/20107701Gn79ZQO8ZK.png
在我們 if 判斷式中,我們有一個 self.x 和 x ,他們指的就不是相同的 x 了 。 self.x 指的是我們在 compare 中宣告的變數 x ,而 self.x 則是 compareX 實例中我們所輸入的值。

這邊我們稍微把程式碼修改,不用 self 去指定 x ,並把 if 判斷是改為 x == x ,來判斷結果:

struct compare {
    var x = 10
    func check(x:Int) -> String {
       var  msg = ""
        if x == x {
            msg = "這兩個 x 是相等的"
        } else {
            msg = "你的輸入的 x 比我們的變數 x 還小"
        }
        return msg
    }
}

結果如下:
https://ithelp.ithome.com.tw/upload/images/20180104/20107701Gm7IE5k2dQ.png

所以這裡如果你沒有用 self 來指定 x ,那麼這兩個 x 永遠都是指為同一個,兩者也是相同的,無法進行比較。

在實例方法中修改值類型

Struct 和 Enum 是值類型(value Type)。 默認情況下,值類型的屬性不能從其實例方法中修改。

但是,如果需要修改特定方法中的 struct 或 enum 的屬性,你可以使用將這個方法進行變異。該方法可以從方法中改變它的屬性,並且當方法結束時,它所做的任何改變都被寫回原始的結構中。方法同樣可以指定一個全新的實例給它隱含的 self 屬性,並且這個新的實例將會在方法結束的時候替換掉現存的這個實例。

你可以選擇在 func 前加入一個 mutating 關鍵字來使用這個行為,下面我們舉一個座標的範例:

struct Coordinate {
    var x:Double  = 0.0 , y:Double = 0.0
    mutating func move(x moveX:Double,y moveY:Double) {
        x += moveX
        y += moveY
    }
}

在這之後我們將它設為一個 position 的實例,給他開始的座標值以及位移的的 x , y 值:

var position = Coordinate(x :5.0 , y : 5.0)
position.move(x: 10.0, y: 10.0)

之後我們將結果印出看看:
https://ithelp.ithome.com.tw/upload/images/20180104/20107701hB1YvScIVO.png

上面中我們在 Coordinate 這個 struct 定義了一個可變異的方法 move,他將 position 實例移動特定的量。這個方法不是返回一個新的點,實際上是修改了被調用的點。將 mutating 關鍵字添加到定義中以使其能夠修改其屬性。


在變異方法中指定自身

變異方法可以將一個全新的實例賦值給隱式的 self 屬性。 上面座標範例可以寫成:

struct Coordinate {
    var x:Double  = 0.0 , y:Double = 0.0
    mutating func move(x moveX:Double,y moveY:Double) {
        self = Coordinate(x: x + moveX , y: y + moveY)
    }
}

枚舉的變異方法可以設置隱含的 self 屬性為相同枚舉裡的不同 case,我們舉一個方向的 enum :

enum direction {
    case up,down,left,righr
}

我們希望他能夠變成上下左右相反的方式,這時我們就能使用異變方法來操作:

enum direction {
   case up, down, left, right
    mutating func antiDirection(){
        switch self{
        case .up:
            self = .down
        case .down:
            self = .up
        case .left:
            self = .right
        case .right:
            self = .left
            
        }
    }
}

這時你把 direction 宣告給一個變數後,在使用其中的 antiDirection() 方法時,就能使它的方向相反:
https://ithelp.ithome.com.tw/upload/images/20180104/201077014djnN7psS3.png

類型方法

你也可以定義在類型本身調用的方法,這種方法被稱作類型方法。你可以在 func 之前使用 static 關鍵字來明確標示這個類型方法。 Class 同樣可以使用 class 關鍵字來允許子類重寫父類對類型方法的實現。

類型方法和實例方法一樣使用點語法調用。不過,你得在 class 上調用類型方法,而不是這個類的實例,舉個例子:

我們一般方式來創建一個加法的方式:

class math {
    func add(_ a:Int , _ b:Int) -> Int {
        return a + b
    }
}
let addResult = math()
print(addResult2.add(5, 10))
//print 15

在調用的時候,我們必須在實例中去調用 add() 這個函數,但如果我們使用類型方法,來創建結果為下:

class math{
    class func add(_ a:Int , _ b:Int) -> Int {
        return a + b
    }
}
let addResult = math.add(10, 5)
//addResult = 15

不僅能夠直接從 math 這個 class 中調用 add(),不需再用實例中調用,我們還可以直接把它結果賦值給一個 addResult 常數。

當然在 struct 也是一樣的方式,只是 func 加上關鍵字換成 static ,下面我們用(x,y)座標來計算面積,並將他作為我們 Result 常數的值:

struct Area {
    static func position(x:Int , y:Int) -> Int {
       var result = x * y
        if result < 0 {
            result = -result
            return result
        } else {
            return result
        }
    }
}

結果:
https://ithelp.ithome.com.tw/upload/images/20180104/20107701pKIaqBmHcz.png


上一篇
Day-15 Swift 語法(11) - Class 與 Struct 的愛恨交織
下一篇
Day-17 Swift 語法(13) - 下標 Subscripts
系列文
Swift 菜鳥的30天30

尚未有邦友留言

立即登入留言