我想实现一个接受某种类类型的Swift方法,但只接受那些符合特定协议的类的实例。例如,在Objective-C中我有这个方法:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter;
其中GPUImageOutput
是特定类,GPUImageInput
是协议。只有符合此协议的GPUImageOutput
类才是此方法的可接受输入。
但是,上面自动生成Swift的版本是
func addFilter(newFilter: GPUImageOutput!)
这消除了GPUImageOutput
类符合GPUImageInput
协议的要求,这将允许传入不兼容的对象(然后在运行时崩溃)。当我尝试将其定义为GPUImageOutput<GPUImageInput>
时,编译器会抛出错误
无法专门化非泛型类型'GPUImageOutput'
我如何在Swift中的参数中进行这样的类和协议特化?
答案 0 :(得分: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")
}
}
现在,您要定义一个方法,该方法接受符合协议ExampleProtocol的ATestClass类型(或子类)的输入参数。 像这样编写方法声明:
func addFilter<T where T: ATestClass, T: ExampleProtocol>(newFilter: T)
{
println(newFilter)
}
你的方法,在swift中重新定义,应该是
func addFilter<T where T:GPUImageOutput, T:GPUImageInput>(newFilter:T!)
{
// ...
}
编辑:
作为您的最后一条评论,在Enum上使用泛型的示例
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)
专注于协议一致性:
enum OptionalValue<T where T:GPUImageOutput, T:GPUImageInput> {
case None
case Some(T)
}
EDIT ^ 2:
即使使用实例变量,也可以使用泛型:
假设您有一个类和一个实例变量,您希望此实例变量仅采用ATestClass
类型的值并且符合ExampleProtocol
class GiveMeAGeneric<T: ATestClass where T: ExampleProtocol>
{
var aGenericVar : T?
}
然后以这种方式实例化它:
var child = ATestClassChild()
let aGen = GiveMeAGeneric<ATestClassChild>()
aGen.aGenericVar = child
如果child
不符合协议ExampleProtocol
,则无法编译
答案 1 :(得分:13)
ObjC的这个方法标题:
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter { ... }
与 Swift 中的此标题相同:
func addFilter<T: GPUImageOutput where T: GPUImageInput>(newFilter: T?) { ... }
两种方法都会接受同一组类
GPUImageOutput
类;和GPUImageInput
协议;和newFilter
是可选的,可以是nil
; 答案 2 :(得分:0)
从Swift 4开始,您可以执行以下操作:
func addFilter(newFilter: GPUImageOutput & GPUImageInput)
http://braking.github.io/require-conformance-to-multiple-protocols/