繁体   English   中英

协议上的关联类型和泛型

[英]Associated types and generics on protocols

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

protocol Protocol {
    typealias ValueType

    var value : ValueType? {get}

    func getProtocolString<A where A : Protocol, A.ValueType == String>() -> A
}

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

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

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

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

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

谢谢

问题在于将协议约束的通用占位符与协议本身混淆。 这是一个更简单的示例,类似于您的代码,试图说清楚:

// first, define a protocol and two structs that conform to it
protocol P { }
struct S1: P { }
struct S2: P { }

// now, a function that returns an object in the form
// of a reference to protocol P
func f() -> P {
    // S1 conforms to P so that’s fine 
    return S1()
}
// ok all well and good, this works fine:
let obj = f()

// now, to do something similar to your example code,
// declare a generic function that returns a generic
// placeholder that is _constrained_ by P
// This will NOT compile:
func g<T: P>() -> T { return S1() }

为什么这不编译?

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

因此,通过下面的示例, T应该替换为S1

let obj1: S1 = g()
// because T needs to be S1, the generic function g above is 
// rewritten by the compiler like this:
func g() -> S1 { return S1() }

这看起来不错。 除了,如果我们想让T成为S2怎么办? S2符合P因此对于T来说是完全合法的值。 但这怎么可行呢:

// require our result to be of type S2
let obj2: S2 = g()
// so T gets replaced with S2… but now we see the problem.
// you can’t return S1 from a function that has a return type of S2.
// this would result in a compilation error that S2 is not
// convertible to S1
func g() -> S2 { return S1() }

这是您获得的错误消息的来源。 您的占位符A可以代表符合Protocol任何类型,但您尝试返回符合该协议的特定类型( AClass )。 所以它不会让你这样做。

看来你是一个有点误解的仿制药。 通用函数在这些函数的调用站点实例化,而不是在每个函数本身。 因此,您编写的类型约束表示此函数返回一个值,其类型可以是Protocol的所有子类型中的任何一种。 因此,对于Protocol所有子类型,函数定义必须在静态上对于A是正确的,不仅对于AClass<String> ,它只是一种类型的Protocol

在任何情况下,我认为没有直接的方法来实现你想要的,至少在当前的Swift中。

这似乎在操场上有效......它是否适用于你想要做的事情?

protocol StringProtocol
{
    typealias ValueType

    var value : ValueType? { get }

    func getProtocolString<A where A: StringProtocol, A.ValueType == String>() -> A
}

class StringClass : StringProtocol
{
    typealias ValueType = String

    var value : ValueType?

    init() { }

    func getProtocolString<A where A: StringProtocol, A.ValueType == String>() -> A
    {
        return StringClass() as A
    }
}

我仍然没有完全遵循您尝试通过此实现实现的要求。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM