2016-03-03 119 views
1

我想使用枚舉來包含泛型函數。這些枚舉將作爲參數傳遞,然後可以相應地執行枚舉中的函數。在枚舉中使用泛型函數

你如何設置在枚舉定義,這樣,他們將被視爲功能泛型類型要執行?請注意,我有可能,我可能要通過各種函數定義。

讓我知道,如果我在這兒可笑。 :)


// Define an enum to pass into my APIs. The S and F are meant to be functions I can define in anyway 
enum FormattedResult<S, F> { 
    case Success(S) 
    case Failure(F) 

    func run<T> (a:T) { 
     switch (self){ 
     case .Success (let completion): 
      // QN: How do I execute this? completion() will of course fail 
      debugPrint(completion) 
     case .Failure (let failure): 
      // QN: Same here 
      debugPrint(failure) 
     } 
    } 
} 


// I want to define a callback for someone else to call. I will be passing this to the error 
var k1 = FormattedResult<(Int)->(), (String)->() >.Success(
    {(a: Int) in 
     debugPrint("xxxxx") 
    }) 

// the APIClient can run this upon completion 
k1.run(2) 

// similarly for failures 
var k2 = FormattedResult<(Int)->() , (String)->()>.Failure(
    {(error: String) in 
     debugPrint(error) 
    } 
    ) 
k2.run("some error happened...") 
+0

'run (a:T)'方法中'T'的用途是什麼? – Kevin

+0

因此調用者可以通過運行函數傳遞一個值來執行y。 –

+0

運行功能應該採用「成功」定義的功能並運行T –

回答

1

在原來的代碼,創建變量​​或k2SF仍然時,雖然定義一個封閉的回調只是佔位符類型,並沒有說什麼S & F必須是。因此,這裏的挑戰是如何定義Swift枚舉來存儲給定函數類型的關聯值。

所以我們的想法是可以使用函數類型,例如(T) -> void作爲枚舉的參數類型,並將函數實現的某些方面與枚舉case值一起留下,以提供何時調用enum函數。

接下來的事情我們並不需要兩個佔位符類型的枚舉,因爲我們只有每個功能run(:)被稱爲即使它可能是StringInt時間有a一種類型。這也是Generic的力量。雖然佔位類型T不說什麼T必須是任何東西,但它說,枚舉(T) -> void兩個a和關聯的值必須是同一類型T的,無論T表示。因此,在這種情況下,一種類型的佔位符就足夠了。

其實,我喜歡你的想法是,來電者可以在價值傳遞給在枚舉run函數來執行,你幾乎沒有在原來的代碼。以下是我上面提到的一個例子。

enum FormattedResult<T> { 
    case Success(((T) -> Void)) 
    case Failure(((T) -> Void)) 

    func run(a:T) { 
     switch self { 
     case Success(let completion): 
      completion(a) 
     case Failure(let completion): 
      completion(a) 
     } 
    } 
} 

let f1 = FormattedResult.Success({ a in 
    debugPrint(a) 
}) 
f1.run(1) 

let f2 = FormattedResult.Failure({ error in 
    debugPrint(error) 
}) 
f2.run("some error happened...") 
+0

非常感謝!很高興你看到這一點。現在嘗試你的解決方案。 :) –

+0

這就是我最後的結局,你怎麼看? https://gist.github.com/mingyeow/ef740dd3d70455a84c01 –

+1

@mingyeow我喜歡它。至於結構''FailureReason'',我可能會使用協議''CustomStringConvertible''實現

struct FailureReason: CustomStringConvertible { var code:Int! var message:String! var description: String { return "Error code \(code): \(message)" } }
Allen

1

你不能把completionfailure作爲一個閉包,因爲你不知道它們是什麼類型。

如果使用SF提供呼叫者需要傳遞的類型,那麼你可以指定你的成功和失敗值的相關類型。

enum FormattedResult<SuccessArg, FailArg> { 
    case Success(SuccessArg -> Void) 
    case Failure(FailArg -> Void) 
} 

注意:如果你想定義一個非空返回值,那麼你就必須要增加兩個通用的參數和替換Void

下一個問題:實現運行功能。

extension FormattedResult { 
    func run(a:AnyObject) { 
     switch (self){ 
     case .Success (let completion): 
      // completion is of type (SuccessArg -> Void) 
      if let successArg = a as? SuccessArg { 
       completion(successArg) 
      } else { 
       fatalError() //?? 
      } 
     case .Failure (let failure): 
      // failure is of type (FailArg -> Void) 
      if let failArg = a as? FailArg { 
       failure(failArg) 
      } else { 
       fatalError() //?? 
      } 
     } 
    } 
} 

我承認困惑什麼運行功能。 run的來電不應該知道是Success還是Failure?因爲您的API的客戶端選擇實施SuccessCase或FailureCase;調用者必須提供成功和失敗的值。

我可能誤會了,這是你在找什麼:

extension FormattedResult { 
    func run(a:SuccessArg, b:FailArg) { 
     switch (self){ 
     case .Success (let completion): 
      // completion is of type (SuccessArg -> Void) 
      completion(a) 
     case .Failure (let failure): 
      // failure is of type (FailArg -> Void) 
      failure(b) 
     } 
    } 
} 
+0

謝謝!這正是我正在尋找的。我瞭解這種困惑,我正在想出自己是否正在將泛型太過分了。將實施並回復給您 –

+0

我不認爲您採用的是泛型太過分,但您可能會濫用枚舉。我認爲用戶想要處理成功案例和失敗案例。 – Kevin

+0

事情是,運行的用戶將要運行成功和失敗。例如,我傳遞了一個formattedResult枚舉,其中定義了成功/失敗函數。當結果成功或失敗時,他們將使用run()來執行它們。合理? –