首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >协议上的关联类型和泛型

协议上的关联类型和泛型
EN

Stack Overflow用户
提问于 2015-03-14 02:39:52
回答 3查看 303关注 0票数 5

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

代码语言:javascript
运行
复制
protocol Protocol {
    typealias ValueType

    var value : ValueType? {get}

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

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

代码语言:javascript
运行
复制
class AClass<T> : Protocol {
    var value : T?       

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

错误是“AClass”不能转换为“A”。

我是不是遗漏了什么?这有可能吗?

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-03-14 12:24:54

问题在于混淆了受协议约束的通用占位符和协议本身。下面是一个简单的示例,类似于您的代码,试图澄清这一点:

代码语言:javascript
运行
复制
// 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

代码语言:javascript
运行
复制
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() }

这个看起来没问题。但是,如果我们希望TS2呢?S2符合P,所以对于T来说是一个完全合法的值。但这怎么能起作用:

代码语言:javascript
运行
复制
// 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)。所以它不会让你这么做。

票数 2
EN

Stack Overflow用户

发布于 2015-03-14 04:01:55

你好像是个小误会。泛型函数在这些函数的调用点实例化,而不是在每个函数本身的主体上实例化。因此,您编写的类型约束表示该函数返回一个值,该值的类型可能是Protocol的所有子类型中的任何一个。因此,函数定义必须对A的所有Protocol子类型进行静态更正,而不仅仅是针对AClass<String>,因为AClass<String>只是一种Protocol类型。

无论如何,我认为没有直接的方法来实现你想要的,至少在当前的Swift中是这样。

票数 0
EN

Stack Overflow用户

发布于 2015-03-14 05:12:36

这好像在操场上起作用..。它对你想做的事情有用吗?

代码语言:javascript
运行
复制
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
    }
}

我仍然没有完全遵循您试图通过这个实现来满足的需求。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29044841

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档