如何指定非泛型Swift类型应符合协议?

Bra*_*son 42 swift

我想实现一个接受某种类类型的Swift方法,但只接受那些符合特定协议的类的实例.例如,在Objective-C中我有这样的方法:

- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter;
Run Code Online (Sandbox Code Playgroud)

哪个GPUImageOutput是特定的类,并且GPUImageInput是一个协议.只有GPUImageOutput符合此协议的类才是此方法的可接受输入.

但是,上面的自动Swift生成的版本是

func addFilter(newFilter: GPUImageOutput!)
Run Code Online (Sandbox Code Playgroud)

这消除了GPUImageOutput类符合GPUImageInput协议的要求,这将允许传入不兼容的对象(然后在运行时崩溃).当我尝试将其定义GPUImageOutput<GPUImageInput>为时,编译器会抛出错误

无法专门化非泛型类型'GPUImageOutput'

我如何在Swift中的参数中进行这样的类和协议专门化?

Lom*_*baX 23

你必须迅速使用泛型,这样:

给出这些协议,主类和子类的示例声明:

protocol ExampleProtocol {
    func printTest()   // classes that implements this protocol must have this method
}

// an empty test class
class ATestClass
{

}

// a child class that implements the protocol
class ATestClassChild : ATestClass, ExampleProtocol
{
    func printTest()
    {
        println("hello")
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您要定义一个方法,该方法接受符合协议ExampleProtocol的ATestClass类型(或子类)的输入参数.像这样编写方法声明:

func addFilter<T where T: ATestClass, T: ExampleProtocol>(newFilter: T)
{
    println(newFilter)
}
Run Code Online (Sandbox Code Playgroud)

你的方法,在swift中重新定义,应该是

func addFilter<T where T:GPUImageOutput, T:GPUImageInput>(newFilter:T!)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

编辑:

作为你的最后一条评论,一个关于Enum的泛型的例子

    enum OptionalValue<T> {
        case None
        case Some(T)
    }
    var possibleInteger: OptionalValue<Int> = .None
    possibleInteger = .Some(100)
Run Code Online (Sandbox Code Playgroud)

专注于协议一致性:

    enum OptionalValue<T where T:GPUImageOutput, T:GPUImageInput> {
        case None
        case Some(T)
    }
Run Code Online (Sandbox Code Playgroud)

编辑^ 2:

你甚至可以使用实例变量来使用泛型:

假设您有一个类和一个实例变量,您希望此实例变量仅采用该类型的值ATestClass并且符合ExampleProtocol

class GiveMeAGeneric<T: ATestClass where T: ExampleProtocol>
{
    var aGenericVar : T?
}
Run Code Online (Sandbox Code Playgroud)

然后以这种方式实例化它:

    var child = ATestClassChild()
    let aGen = GiveMeAGeneric<ATestClassChild>()
    aGen.aGenericVar = child
Run Code Online (Sandbox Code Playgroud)

如果child不符合协议ExampleProtocol,则不会编译


hol*_*lex 13

来自ObjC的这个方法标题:

- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter { ... }
Run Code Online (Sandbox Code Playgroud)

Swift中的此标题相同:

func addFilter<T: GPUImageOutput where T: GPUImageInput>(newFilter: T?) { ... }
Run Code Online (Sandbox Code Playgroud)

两种方法都会接受同一组类

  • 这是基于GPUImageOutput阶级; 和
  • 符合GPUImageInput协议; 和
  • newFilter是可选的,它可以是nil;