我一直在研究具有不同类型的泛型类的数组。用一些示例代码来解释我的问题是最简单的:
// Obviously a very pointless protocol...
protocol MyProtocol {
var value: Self { get }
}
extension Int : MyProtocol { var value: Int { return self } }
extension Double: MyProtocol { var value: Double { return self } }
class Container<T: MyProtocol> {
var values: [T]
init(_ values: T...) {
self.values = values
}
func myMethod() -> [T] {
return values
}
}
现在,如果我尝试创建像这样的容器数组:
var containers: [Container<MyProtocol>] = []
我得到错误:
协议“ MyProtocol”只能用作通用约束,因为它具有“自身”或相关的类型要求。
要解决这个问题,我可以使用[AnyObject]
:
let containers: [AnyObject] = [Container<Int>(1, 2, 3), Container<Double>(1.0, 2.0, 3.0)]
// Explicitly stating the types just for clarity.
但是现在在枚举时出现了另一个“问题” containers
:
for container in containers {
if let c = container as? Container<Int> {
println(c.myMethod())
} else if let c = container as? Container<Double> {
println(c.myMethod())
}
}
如您在上面的代码中看到的那样,container
在两种情况下,确定相同方法的类型后都会调用它。我的问题是:
是否有Container
比将类型转换为每种可能的类型更好的方法来获取正确的类型Container
?还是我忽略了其他事情?
有一种方法-做某事-一种。使用协议,有一种方法可以消除类型限制,并且仍然可以得到所需的结果,但这并不总是很漂亮。这是我根据您的情况提出的协议:
protocol MyProtocol {
func getValue() -> Self
}
extension Int: MyProtocol {
func getValue() -> Int {
return self
}
}
extension Double: MyProtocol {
func getValue() -> Double {
return self
}
}
请注意,value
您最初放在协议声明中的属性已更改为返回对象的方法。
那不是很有趣。
但是现在,由于您已经摆脱value
了协议中的属性,因此MyProtocol
可以将其用作类型,而不仅仅是类型约束。您的Container
班级甚至都不再需要泛型。您可以这样声明:
class Container {
var values: [MyProtocol]
init(_ values: MyProtocol...) {
self.values = values
}
func myMethod() -> [MyProtocol] {
return values
}
}
而且由于Container
不再通用,因此您可以创建一个Array
,Container
然后遍历它们,打印myMethod()
方法的结果:
var containers = [Container]()
containers.append(Container(1, 4, 6, 2, 6))
containers.append(Container(1.2, 3.5))
for container in containers {
println(container.myMethod())
}
// Output: [1, 4, 6, 2, 6]
// [1.2, 3.5]
诀窍是构造 仅包含通用功能且对符合类型没有其他要求 的协议 。 如果您可以避免这样做,那么可以将协议用作类型,而不仅仅是类型约束。
另外(如果您想这样称呼),您的MyProtocol
值数组甚至可以混合符合的不同类型MyProtocol
。因此,如果您给出这样String
的MyProtocol
扩展名:
extension String: MyProtocol {
func getValue() -> String {
return self
}
}
您实际上可以Container
使用混合类型初始化a :
let container = Container(1, 4.2, "no kidding, this works")
[警告-我正在一个在线游乐场进行测试。我还不能在Xcode中对其进行测试…]
编辑:
如果你仍然想Container
成为通用的,只能容纳一个类型的对象,就可以完成,通过使 之 符合自己的协议:
protocol ContainerProtocol {
func myMethod() -> [MyProtocol]
}
class Container<T: MyProtocol>: ContainerProtocol {
var values: [T] = []
init(_ values: T...) {
self.values = values
}
func myMethod() -> [MyProtocol] {
return values.map { $0 as MyProtocol }
}
}
现在,您 仍然 可以拥有一个[ContainerProtocol]
对象数组,并通过调用它们进行迭代myMethod()
:
let containers: [ContainerProtocol] = [Container(5, 3, 7), Container(1.2, 4,5)]
for container in containers {
println(container.myMethod())
}
也许这仍然对您不起作用,但是现在Container
仅限于一种类型,但是您仍然可以遍历ContainterProtocol
对象数组。
Swift 4语言提供了泛型()功能来编写灵活且可重用的函数和类型。 泛型用于避免重复并提供抽象。 Swift 4标准库使用泛型代码构建。 Swift 4中的数组和字典类型属于泛型集合。 使用数组和字典,数组可定义为保存值和值或任何其他类型。 示例代码 当使用playground运行上述程序时,得到以下结果 - 泛型函数:类型参数 泛型函数可用于访问任何数据类型,如或。 当使用playground
Swift 提供了泛型让你写出灵活且可重用的函数和类型。 Swift 标准库是通过泛型代码构建出来的。 Swift 的数组和字典类型都是泛型集。 你可以创建一个Int数组,也可创建一个String数组,或者甚至于可以是任何其他 Swift 的类型数据数组。 以下实例是一个非泛型函数 exchange 用来交换两个 Int 值: 实例// 定义一个交换两个变量的函数 func swapTwoInts
我试图使这个JavaScript代码在Swift:k_combinations 到目前为止,我在斯威夫特有这样的记录: 但问题是我的功能打印 当它应该打印的时候 我做错了什么?我不擅长编码,我的javascript技能也不是很好,但javascript对我来说很有用,但在swift中我无法做到这一点。
问题内容: 现在,我希望能够查看so中是否包含对象: 如果您发现此功能属于扩展名。问题是如果将其添加到此: 我收到以下错误: 找不到’==’的重载,该重载接受提供的参数 我了解我可能需要告诉什么样的对象应该在里面,例如:。但这还不起作用: 括号中的语句块是未使用的闭包 非标称类型’T []’无法 扩展 问题答案: 使用Swift时,我们需要考虑是否有一个 函数 可以解决问题-在类的方法之外。 就像
问题内容: 是否可以为特殊/构造的泛型类型扩展泛型类?我想使用一种方法来扩展Int Arrays,以计算其元素的总和。 例如 问题答案: Swift 5.x:
问题内容: 我正在尝试创建一个泛型类型的数组。我收到错误消息: 我很困惑。任何线索为什么会这样。 问题答案: 其背后的原因是,您不能创建通用或参数化类型的数组,而只能 创建可验证的 类型(即可以在运行时推断出的类型)。 尽管可以将此类数组类型 声明 为变量或方法参数。这有点不合逻辑,但这就是Java的样子。 Java泛型和集合在第6章中广泛讨论了此问题和相关问题。