2016-03-03 86 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()来执行它们。合理? –