2016-09-21 49 views
1

我想用自定義的運算符和函數編寫一些類似流利的api。這裏是什麼,我正在尋找一個例子:自定義運算符的Swift-like api設計

var result = [Section]() 

result +++= Section() 
    .appendTitle(title) 
    .appendPhotos(photos) 

result +++= Section() 
    .appendSomething(sth) 
    .appendPhotos(photos) 
    .appendAnything() 

return result 

爲了做到這一點,我已經聲明瞭兩個運營商定製:

infix operator +++{ associativity left precedence 95 } 

funC+++(lhs : [Section], rhs : Section) -> [Section] { 
    var result = lhs 
    result.append(rhs) 
    return result 
} 

infix operator +++= { associativity left precedence 95 } 

funC+++=(inout lhs : [Section], rhs : Section) { 
    lhs = lhs +++ rhs 
} 

,當然還有正確的擴展爲Section結構:

extension Section { 
    mutating func appendTitle(title: String?) -> Section { 
     guard let unwrappedTitle = title 
      else { return self } 

     ... 

     return self 
    } 

    mutating func appendPhotos(photos: [Photo]?) -> Section { 
     ... 
    } 

    ... 
} 

不幸的是預期還是不行...

result +++= Section()單獨是正確的,但是當我添加.append它不編譯。

的第一個消息是:Passing value of type '[Section]' to an inout parameter requires explicit '&'

然後我試圖把一個&result前面(但我從來沒有做過它a += 1)有一個第二條消息:Cannot use mutating member on immutable value: function call returns immutable value

因此,如果任何人都可以幫助,這將不勝感激。

我使用的是Swift 2.2和Xcode 7.

回答

3

嗯,你已經找到了解決辦法。那很棒!

但請允許我解釋這裏發生了什麼。

讓我們仔細看看您之前的實施。

extension Section { 
    mutating func appendTitle(title: String?) -> Section { 

     guard let unwrappedTitle = title else { return self } 
     self.title = unwrappedTitle 
     return self 
    } 

    mutating func appendPhotos(photos: [Photo]?) -> Section { 
     guard let unwrappedPhotos = photos else { return self } 
     self.photos = unwrappedPhotos 
     return self 
    } 
} 

我們知道(至少現在)運算符重載函數是絕對正確的,沒有錯。

給定擴展正在改變參數的值,因此它應該是變異的,它是。那麼,爲什麼錯誤:

「不能使用不可變值可變成員:函數調用返回 不變的價值」

原因:當「appendTitle」或「appendPhotos」被調用時,它返回一個自我的副本。不完全相同的參考!

這是因爲迅速處理不變性的方式。如果成員屬性的值更改爲值類型,則會將該值分配給各個成員來創建副本。

因此,當你寫:Section().appendTitle(title).appendPhotos(photos)

Section()返回self即第一個不可改變的版本的副本。 因此一個人不可能appendTitle它,或不能一般mutat它。

就能解決的:

var section = Section() section.appendTitle(title).appendPhotos(photos)

但現在appendTitle(title)返回self即第一個不可改變的版本的副本。同樣的問題依然存在。

你所做的是不是用self改變任何東西,而是創建了一個新實例,這次是一個使用var的可變元素。突變它並返回它。現在它不是自我變異,因此它不需要是mutating func

你提供的解決方案在這裏工作得很好,但實際上它是一種黑客攻擊,這裏需要說明我現在要說Swift中的一個「bug」。

其他解決方案可以更改struct Sectionclass Section。在那裏你不需要創建var result,只需更改屬性並返回即可。

這是我對SO :)

+0

謝謝您的回答第一個答案,那就是在迅速的通病,因爲多年的面向對象的,我們通常(至少部分地)忘記了按值傳遞參數而不是通過參考有時會導致對語言的誤解。無論如何,謝謝你,因爲這是你的第一個答案,我會自豪地接受它,因爲它比我的更明確。 ;) – Zaphod

+0

@Zaphod,你已經做了一個很好的觀點。隨着多年的面向對象程序設計,很容易忽視功能語言的使用。 Swift是一種功能性語言,它關乎不變性。感謝接受。 :) – Gurdeep

0

我發現了!!!

這些方法不應該是變異:

func appendTitle(title: String?) -> Section { 
    guard let unwrappedTitle = title 
     else { return self } 

    var result = self 

    ... // Work with result instead of self!!! 

    return result 
}