2016-09-21 4 views
1

カスタム演算子と関数を使用して流暢なようなAPIを作成したいと思います。ここでは私が探しているものの例です:カスタムオペレーターによる素早く流暢なAPIデザイン

var result = [Section]() 

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

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

return result 

ことを行うために、私は2つのカスタム演算子を宣言した:

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のためにそれをやったことがない)2番目のメッセージがあります:Cannot use mutating member on immutable value: function call returns immutable value

だから、誰もができれば助けていただければ幸いです。

私はそれを見つけたスウィフト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」が呼び出されると、それはA返す

理由自己のコピー。全く同じ参照ではありません!

これは、迅速に不変性を処理する方法のためです。値タイプに対してメンバープロパティの値が変更された場合、そのメンバーに値を割り当ててコピーが作成されます。したがって

、あなたが書いた:Section().appendTitle(title).appendPhotos(photos)

Section()は、すなわち、セクションの不変バージョン自己のコピーを返します。 したがって、それにはappendTitleを入れることはできません、またはそれを一般に突然変異させることはできません。解決することができ

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

しかし、今appendTitle(title)は、すなわち、セクションの不変バージョン自己のコピーを返します。同じ問題が続く。

selfで何かを変更する代わりに、新しいインスタンスを作成しました。今回はvarを使用して変更可能なインスタンスを作成しました。それを突然変異させて返しました。今ではそれ自体が変異していないので、mutating funcである必要はありません。

あなたが提供したソリューションはここでもうまくいきますが、現時点ではSwiftの「バグ」とは何かをカバーするために必要なハックです。

その他のソリューションはstruct Sectionからclass Sectionに変更できます。 var resultを作成する必要はありません。プロパティを変更して戻るだけです。

これは、あなたの答えのおかげでは、それが原因OOPの年の、迅速に共通の問題ですが、通常は(少なくとも部分的に)我々の値でパラメータを渡すことを忘れSO上の私の最初の答え:)

+0

です参考にすることなく、言語の誤解を招くことがあります。とにかくありがとう、それはあなたの最初の答えであるので、私は誇らしげにそれを受け入れるでしょう、なぜなら、それは私よりもはっきりとしているからです。 ;) – Zaphod

+0

@Zaphod、あなたは本当に良い点を作った。長年のOOPでは、機能的言語の見通しを見落とすのは非常に簡単です。 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 
}