Generics 为什么泛型不';不编译?

Generics 为什么泛型不';不编译?,generics,swift,Generics,Swift,我试图使用泛型实现以下结构。获取编译器错误,无法找出原因 class Translator<T:Hashable> {...} class FooTranslator<String>:Translator<String> {...} 类转换器{…} 类FootTranslator:转换器{…} 其思想是翻译器使用T作为字典中的键类型。例如,可以是字符串或枚举。子类提供了具体的字典 但它失败了,因为:“类型‘String’不符合协议‘Hashable’”

我试图使用泛型实现以下结构。获取编译器错误,无法找出原因

class Translator<T:Hashable> {...}

class FooTranslator<String>:Translator<String> {...}
类转换器{…}
类FootTranslator:转换器{…}
其思想是翻译器使用T作为字典中的键类型。例如,可以是字符串或枚举。子类提供了具体的字典

但它失败了,因为:“类型‘String’不符合协议‘Hashable’”

但是字符串符合Hashable。它也不适用于Int,Int也符合Hashable

如果我删除类型约束,只是为了测试(我还必须禁用字典,因为我不能使用任何不可散列的键),它会编译

class Translator<T> {...}

class FooTranslator<String>:Translator<String> {...}
类转换器{…}
类FootTranslator:转换器{…}

我做错了什么?

我不是一个敏捷的开发人员,但在Java中也遇到过类似的问题,我怀疑问题在于,现在您正在声明一个名为
String
的类型参数,因为您正在声明
类FootTranslator
-所以
Translator
中的类型参数就是那个类型参数,没有任何限制。我猜想,您根本不需要类型参数(也就是说,您不希望您的
FooTranslator
本身是泛型类)

如评论中所述,在Swift中。您可能会声明一个一次性类型参数,如下所示:

class FooTranslator<T>:Translator<String>
或者甚至以一种可怕的方式将二者混合,如果您真的想要一个子类,但不想以通用的方式引用它:

class GenericFooTranslator<T>:Translator<String>
typealias FooTranslator = GenericFooTranslator<Int>
class GenericFootTranslator:转换器
typealias FootTranslator=通用FootTranslator

(注意这里的
Int
不是
String
,为了表明
Translator
中的
T
FooTranslator
中的
T
不同)

首先,让我们解释一下错误:

class Foo<T: Hashable>

class SubFoo<T: Hashable> : Foo<T> { }
鉴于:

class Foo<T:Hashable> { }

class SubFoo<String> : Foo<String> { }
由于使用了未声明的类型,此行为
T
生成一个错误

然后,如果我们将行更改为:

class SubFoo<T> : Foo<T> { }
这是完全有效的Swift,它编译得很好


相反,如果我们想要的是对泛型类进行子类化,并向泛型类添加方法或属性,那么我们需要的是一个类或协议,它将使我们的泛型更具体地满足我们的需要

回到最初的问题,让我们首先消除错误:

class Foo<T: Hashable>

class SubFoo<T: Hashable> : Foo<T> { }
这是完全正确的

另外,请注意,我们实际上不必从
哈希表继承:

protocol MyProtocol { }
class Foo<T: Hashable> { }
class SubFoo<T: Hashable, MyProtocol> { }
协议MyProtocol{}
类Foo{}
类子对象{}
这也是完全正确的

但是,请注意,无论出于何种原因,Swift都不允许您在这里使用类。例如:

class MyClass : Hashable { }

class Foo<T: Hashable> { }
class SubFoo<T: MyClass> : Foo<T> { }
classmyclass:Hashable{}
类Foo{}
类subfo:Foo{}
斯威夫特神秘地抱怨“T”不符合“Hashable”(即使我们添加了必要的代码使其符合要求)


最后,正确的方法,也是最快捷的合适方法是编写一个新的协议,该协议继承自“Hashable”,并添加您需要的任何功能


我们的子类接受一个
字符串并不十分重要。重要的是,无论我们的子类接受什么,它都具有我们所做的任何事情所需的必要方法和属性。

不是这样。关于这一点,有一个快速的问题/限制,请参见@lxx:Ick。我怀疑这仍然是原因,但y您需要一个不同的解决方案。我已经用一个可能的解决方案编辑了我的答案,以供尝试。@Ixx:对-我不清楚您是否因为其他原因需要一个子类,其中类型别名不合适。我将进一步编辑答案。
class SubFoo<T: String> : Foo<T> { }
protocol MyProtocol : Hashable { }

class Foo<T: Hashable> { }
class SubFoo<T: MyProtocol> : Foo<T> { }
protocol MyProtocol { }
class Foo<T: Hashable> { }
class SubFoo<T: Hashable, MyProtocol> { }
class MyClass : Hashable { }

class Foo<T: Hashable> { }
class SubFoo<T: MyClass> : Foo<T> { }