如何在Swift中实现与Generic回调接口等效的java



在java中,您可以声明一个类似的接口

public interface Foo<T>
{
    public void doFoo(T result);
}

你可以在另一种方法中使用它作为类型参数,比如

public void doSomeAsyncTask(final Foo<MyObject> foo)
{
    Runnable asyncRunnable = new Runnable()
    {
        @Override
        void run()
        {
            MyObject result;
            // do task to get result
            foo.doFoo(result);
        }
    };
    Thread asyncThread = new Thread(asyncRunnable);
    asyncThread.start();
}
foo.doFoo(result);
}

正如您所看到的,我使用该接口从运行在不同线程上的某个异步任务进行回调。

更新

根据这个指南,我提出了一个类似于这个的解决方案

public protocol GenericProtocol {
    associatedType T
    func magic(result:T)
}
class GenericProtocolThunk<T> : GenericProtocol {
    private let _magic : (T)
    init<P : GenericProtocol where P.T == T>(_dep : P) {
        _magic = p.magic
    }
    func magic(result: T) {
        _magic(result)
    }
}

现在,在我的doSomeAsyncTask方法中,我可以将GenericProtocolThunk<MyObject>作为参数类型传递。这是实现我在问题中所问的正确方法吗?老实说,我觉得它很难看。

我认为你的问题实际上可以归结为你链接到的博客文章中也提到的内容:

"Swift中的协议可以通过抽象类型的成员进行泛型,而不是而不是参数化。因此,协议本身不能再可以用作类型,但只能用作泛型约束。"

基于thunk的(丑陋的)解决方法看起来确实解决了你的问题,尽管为了验证这一点,如果你在问题中对Java和Swift示例都使用了类似的术语,并且它们是完整的,包括实际包含doSomeAsyncTask方法的类型,以避免可能的混淆,这将有所帮助。

如果你能稍微改变一下配方,我可以想出一些更适合Swift的替代方案。

如果你也可以用协议来描述Result,那么这种语言就不会那么反对你了。与Java相比,遵守协议(即实现接口)也不仅仅局限于类类型,如下面的示例所示,因此可以说,与Java中相比,您可以从该语言中获得更多:

import Foundation
protocol Result {
    // any restrictions on Result that you need.
}
class A:Result { }
struct B:Result { }
enum C:Result { case X }
protocol Foo {
    func doFoo(result:Result) -> Void
}
class Bar {
    func doSomeAsyncTask(foo:Foo) -> Void {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
            foo.doFoo(A())
            foo.doFoo(B())
            foo.doFoo(C.X)
        }
    }
}

我最近才在一类相关问题中使用的另一种选择是将结果建模为枚举可能的结果类型的枚举,如下所示(顺便说一句,在下面的代码示例中,BibliographyItemInlineMathFragmentEquationBlockElementInlineElement中的每一个都是协议,而不是具体类型):

public enum Result {
    case None
    case BibliographyItems([BibliographyItem])
    case InlineMathFragments([InlineMathFragment])
    case Equations([Equation])
    case BlockElements([BlockElement])
    case InlineElements([InlineElement])
}

这在您的结果来自某个已知的结果类型集的情况下很方便,并且您通常需要以某种条件形式处理它们。

您可能需要将其简化为:

func doSomeAsyncTask<T>(callback: (T)->Void)

看看这个伟大的视频:

Rob Napier:超越地壳:真实世界协议

最新更新