讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 2.14 柯裡化函數 >

2.14 柯裡化函數

再次回到makeRoundedRectangleMaker:


func makeRoundedRectangleMaker(sz:CGSize) ->  -> UIImage {
    return {
        imageOfSize(sz) {
            let p = UIBezierPath(
                roundedRect: CGRect(origin:CGPointZero, size:sz),
                cornerRadius: 8)
            p.stroke
        }
    }
}  

我對上述方法的一個地方不太滿意:它所創建的圓角矩形的尺寸是個參數(sz),不過圓角矩形的cornerRadius卻是硬編碼的8,我希望能夠為圓角半徑指定值。有兩種方式可以做到這一點。一種是為makeRoundedRectangleMaker本身再提供一個參數:


func makeRoundedRectangleMaker(sz:CGSize, _ r:CGFloat) ->  -> UIImage {
    return {
        imageOfSize(sz) {
            let p = UIBezierPath(
                roundedRect: CGRect(origin:CGPointZero, size:sz),
                cornerRadius: r)
            p.stroke
        }
    }
}  

然後像下面這樣調用:


let maker = makeRoundedRectangleMaker(CGSizeMake(45,20), 8)  

還有另外一種方式。現在,makeRoundedRectangleMaker所返回的函數不接收參數,我們可以讓它接收一個參數:


func makeRoundedRectangleMaker(sz:CGSize) -> (CGFloat) -> UIImage {
    return {
        r in
        imageOfSize(sz) {
            let p = UIBezierPath(
                roundedRect: CGRect(origin:CGPointZero, size:sz),
                cornerRadius: r)
            p.stroke
        }
    }
}  

現在,makeRoundedRectangleMaker所返回的函數會接收一個參數,因此在調用時需要將這個參數提供給它:


let maker = makeRoundedRectangleMaker(CGSizeMake(45,20))
self.myImageView.image = maker(8)  

如果不需要保存maker供其他地方使用,那就可以在一行完成所有這些事情:函數調用會生成一個函數,我們再立刻調用該函數來獲取圖片:


self.myImageView.image = makeRoundedRectangleMaker(CGSizeMake(45,20))(8)  

如果函數返回的函數接收一個參數,就像該示例這樣,那麼它就叫作柯裡化函數(為了紀念計算機科學家Haskell Curry)。Swift提供了柯裡化函數的便捷聲明方式;可以省略第1個箭頭運算符與頂層匿名函數,如以下代碼所示:


func makeRoundedRectangleMaker(sz:CGSize)(_ r:CGFloat) -> UIImage {
   return imageOfSize(sz) {
       let p = UIBezierPath(
           roundedRect: CGRect(origin:CGPointZero, size:sz),
           cornerRadius: r)
       p.stroke
   }
}  

表達式(sz:CGSize)(_r:CGFloat)(一行有兩個參數列表,並且中間沒有箭頭運算符)表示「Swift,請對該函數進行柯裡化」。Swift會將函數劃分到兩個函數中,一個是makeRoundedRectangleMaker,接收CGSize參數,另一個是匿名函數,接收CGFloat。代碼看起來好像是makeRoundedRectangleMaker會返回一個UIImage,不過實際上它返回的是一個函數,該函數會返回一個UIImage,就像之前那樣。我們可以像之前所採用的兩種方式那樣調用它。