如何在Swift中使用具有关联类型的协议作为返回值?

时间:2015-08-08 16:21:56

标签: swift generics

我尝试使用具有关联类型的协议作为类func的返回值。

stackoverflow上的

Another post是关于同一个问题的,基于这篇文章的回答,我尝试了以下内容:

// addArg takes a single Int argument and returns something, 
// which is capable of adding a another Int argument
class OpWithNoArg {
    func addArg<OP: OpWithOneArg where OP.ArgType == Int>(arg: Int) -> OP {
        return OpWithOneArgImpl() // (1) error here !
    }
}

// a protocol with associated type, which allows adding another
// argument of a not yet specified type
protocol OpWithOneArg {
    typealias ArgType
    func addAnotherArg(arg: ArgType)
}

// an implementation of the protocol above, 
// which fixes the associated type to an Int
class OpWithOneArgImpl : OpWithOneArg {
    typealias ArgType = Int
    func addAnotherArg(arg: Int) {
        // ...
    }
}

标有(1)的Xcode 7.0 Beta 4中的错误是

  

无法转换类型&#39; OpWithOneArgImpl&#39;的返回表达式至   预期回报类型&#39; OP&#39;

如果我将返回值更改为可选,并且返回nil,则示例将成功编译:

// return null  
class OpWithNoArg {
    func addArg<OP: OpWithOneArg where OP.ArgType == Int>(arg: Int) -> OP? {
        // return OpWithOneArgImpl()
        return nil
    }
}

这种方式是使用具有关联类型的协议作为swift中的返回值,如果是这样的话,如何修复上面提到的编译器错误?

提前致谢!

修改

在Java中,代码类似于以下代码段。我试图在Swift中找到一种方法来实现同样的目标。

class C {
    <T> P<T> f(T arg) {
        return new PImpl();
    }
}

interface P<S> {
    void g(S arg);
}

class PImpl<S> implements P<S> {
    PImpl() {}
    public void g(S arg) {}
}

1 个答案:

答案 0 :(得分:2)

不清楚你想要实现的目标,但是这个错误源于你的addArg函数中你定义了一个通用类型OP,它通常应该在函数的参数和正文中使用

相反,您返回非泛型类型,试图强制将其视为通用的“OP。”。

快速修复可能会强制转换为返回对象的OP

return OpWithOneArgImpl() as !OP

但我不推荐它。

在您的示例中,addArg将始终返回OpWithOneArgImpl,因此可以将其定义为func addArg(arg: Int) -> OpWithOneArgImpl

希望这有帮助。

修改

可能这不是你想要达到的目标,但希望它可以提供帮助 更清楚地解释我的意图。

protocol OpWithOneArg {
    typealias ArgType
    func addAnotherArg(arg: ArgType)
    init() // Must have a init with no argument
}


class OpWithOneArgImpl : OpWithOneArg {
    typealias ArgType = Int
    func addAnotherArg(arg: Int) {
        // ...
    }
    required init() {
        // init implementation
    }
}

class OpWithNoArg {
    func addArgWithOPType<OP: OpWithOneArg where OP.ArgType == Int>(op: OP.Type, arg: Int) -> OP {
        return OP() // Here we use the init
    }
}

let foo = OpWithNoArg()
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)

修改

也许您可能会调查泛型类型的使用:

protocol OpWithOneArg {
    typealias ArgType
    func addAnotherArg(arg: ArgType)
    init() // Must have a init with no argument
}


class OpWithOneArgImpl<T> : OpWithOneArg { // Generic implementation confirming to protocol
    typealias ArgType = T
    func addAnotherArg(arg: T) {
        // ...
    }
    required init() {
        // init implementation
    }
}


class OpWithNoArg {
    func addArgWithOPType<OP: OpWithOneArg>(op: OP.Type, arg: OP.ArgType) -> OP {
        return OP() // Here we use the init
    }
}

let foo = OpWithNoArg()

// OpWithOneArgImpl<Int>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3) 

// OpWithOneArgImpl<String>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: "Hello")