【问题标题】:Using generic functions in enums在枚举中使用泛型函数
【发布时间】:2016-03-03 01:07:03
【问题描述】:

我正在尝试使用枚举来包含通用函数。这些枚举将作为参数传递,然后可以相应地执行枚举中的函数。

您将如何在枚举定义中设置泛型类型,以便将它们识别为要执行的函数?请注意,我可能有各种想要传入的函数定义。

如果我在这里很可笑,请告诉我。 :)


// 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...")

【问题讨论】:

  • T在run&lt;T&gt; (a: T)方法中的作用是什么?
  • 所以调用者可以传入一个值,由run函数执行。
  • 运行函数应该是把"success"定义的函数用T运行

标签: swift generics enums


【解决方案1】:

在原始代码中,虽然在创建变量k1 或k2 时将闭包定义为回调,但S 和F 仍然只是占位符类型,并没有说明S 的含义&F 必须是。因此,这里的挑战是如何定义 Swift 枚举来存储给定函数类型的关联值。

所以我们的想法是我们可以使用诸如(T) -&gt; void 之类的函数类型作为枚举的参数类型,并在调用枚举函数时将函数实现的某些方面与枚举案例值一起提供。

接下来我们不需要在枚举中使用两种占位符类型,因为每次调用函数 run(:) 时我们只有一种类型的 a,即使它可能是 String 或 Int。这也是Generic 的力量所在。尽管占位符类型T 没有说明T 必须是什么,但它确实说明a 和枚举(T) -&gt; void 的关联值必须是相同的类型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...")

【讨论】:

  • 非常感谢!很高兴你明白这一点。立即尝试您的解决方案。 :)
  • 这就是我的结果,你觉得呢? gist.github.com/mingyeow/ef740dd3d70455a84c01
  • @mingyeow 我喜欢。至于结构FailureReason,我可能会使用协议CustomStringConvertible
    struct FailureReason: CustomStringConvertible { var code:Int!变量消息:字符串! var description: String { return "错误代码(code): (message)" } }
  • 完成!谢谢艾伦。顺便说一句,你能指出我的代码中的主要错误是什么吗?你的要简单得多,但效果很好
  • @mingyeow 我刚刚修改了我的答案。请作为参考。干杯:)
【解决方案2】:

您不能将 completion 或 failure 视为闭包,因为您不知道它们是什么类型。

如果您使用S 和F 提供调用者需要传入的类型,那么您可以指定您的成功和失败值的关联类型。

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

注意:如果您想定义一个非 void 返回值,那么您必须再添加两个通用参数并替换 Void。

下一个问题:实现run函数。

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 函数的含义感到困惑。 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)
        }
    }
}

【讨论】:

  • 谢谢!这正是我正在寻找的。我理解这种困惑,我正在自己弄清楚我是否将仿制药走得太远。将实施并回复您
  • 我不认为你把泛型走得太远了,但你可能误用了枚举。我认为用户希望同时处理成功案例和失败案例。
  • 问题是,run 的用户想要运行成功和失败。例如,我正在向我的 apiclient 传递一个 formattedResult 枚举,其中定义了成功/失败函数。当结果成功或失败时,他们将使用 run() 执行它们。有意义吗?
  • 这就是我最终得到的结果:gist.github.com/mingyeow/ef740dd3d70455a84c01
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
相关资源
最近更新 更多