协议上的关联类型和泛型

fbe*_*rdo 5 generics ios swift

我试图在协议中声明一个函数,该函数强制符合它的类型返回相同协议的值,但具有特定的关联类型:

protocol Protocol {
    typealias ValueType

    var value : ValueType? {get}

    func getProtocolString<A where A : Protocol, A.ValueType == String>() -> A
}
Run Code Online (Sandbox Code Playgroud)

这编译.当我尝试创建一个符合它的类时,我得到了错误:

class AClass<T> : Protocol {
    var value : T?       

    func getProtocolString<A where A : Protocol, A.ValueType == String>() -> A {
        return AClass<String>()
    }
}
Run Code Online (Sandbox Code Playgroud)

错误是'AClass'不能转换为'A'.

我错过了什么吗?这甚至可能吗?

谢谢

Air*_*ity 2

问题在于将受协议约束的通用占位符与协议本身混淆了。Here\xe2\x80\x99s 是一个更简单的示例,类似于您的代码,尝试使其清晰:

\n\n
// first, define a protocol and two structs that conform to it\nprotocol P { }\nstruct S1: P { }\nstruct S2: P { }\n\n// now, a function that returns an object in the form\n// of a reference to protocol P\nfunc f() -> P {\n    // S1 conforms to P so that\xe2\x80\x99s fine \n    return S1()\n}\n// ok all well and good, this works fine:\nlet obj = f()\n\n// now, to do something similar to your example code,\n// declare a generic function that returns a generic\n// placeholder that is _constrained_ by P\n// This will NOT compile:\nfunc g<T: P>() -> T { return S1() }\n
Run Code Online (Sandbox Code Playgroud)\n\n

为什么这不能编译?

\n\n

泛型函数的工作方式是,在编译时,当您调用该函数时,编译器会决定占位符T需要是什么类型,然后为您编写一个函数,其中所有出现的 都T替换为该类型。

\n\n

因此,在下面的示例中,T应替换为S1

\n\n
let obj1: S1 = g()\n// because T needs to be S1, the generic function g above is \n// rewritten by the compiler like this:\nfunc g() -> S1 { return S1() }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这看起来不错。除了,如果我们想T成为这样怎么办S2S2符合Pso 是 的一个完全合法的值T。但这怎么行得通:

\n\n
// require our result to be of type S2\nlet obj2: S2 = g()\n// so T gets replaced with S2\xe2\x80\xa6 but now we see the problem.\n// you can\xe2\x80\x99t return S1 from a function that has a return type of S2.\n// this would result in a compilation error that S2 is not\n// convertible to S1\nfunc g() -> S2 { return S1() }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是您收到的错误消息的来源。您的占位符A可以代表任何符合 的类型Protocol,但您试图返回符合该协议的特定类型 ( )。AClass所以它不会\xe2\x80\x99让你这么做。

\n