- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我一直在研究不同类型的泛型类数组。用一些示例代码来解释我的问题是最简单的:
// 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>] = []
我得到错误:
Protocol 'MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements.
要解决这个问题,我可以使用 [AnyObject]
:
let containers: [AnyObject] = [Container<Int>(1, 2, 3), Container<Double>(1.0, 2.0, 3.0)]
// Explicitly stating the types just for clarity.
但是现在通过容器
枚举时出现了另一个“问题”:
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
?或者还有其他我忽略的东西吗?
最佳答案
有一种方法 - 有点 - 做你想做的事 - 有点。有一种方法可以通过协议(protocol)消除类型限制并仍然获得您想要的结果,有点,但它并不总是很漂亮。以下是我针对您的情况提出的协议(protocol):
protocol MyProtocol {
func getValue() -> Self
}
extension Int: MyProtocol {
func getValue() -> Int {
return self
}
}
extension Double: MyProtocol {
func getValue() -> Double {
return self
}
}
请注意,您最初放入协议(protocol)声明中的 value
属性已更改为返回对象的方法。
这不是很有趣。
但是现在,因为您已经摆脱了协议(protocol)中的 value
属性,所以 MyProtocol
可以用作类型,而不仅仅是类型约束。您的 Container
类甚至不再需要是通用的。您可以这样声明:
class Container {
var values: [MyProtocol]
init(_ values: MyProtocol...) {
self.values = values
}
func myMethod() -> [MyProtocol] {
return values
}
}
并且由于 Container
不再是通用的,您可以创建 Container
的 Array
并遍历它们,打印结果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]
诀窍是构建一个仅包含泛型函数并且不对符合类型提出任何其他要求的协议(protocol)。如果您可以做到这一点,那么您可以将该协议(protocol)用作类型,而不仅仅是作为类型约束。
作为奖励(如果你想这样调用它),你的 MyProtocol
值数组甚至可以混合符合 MyProtocol
的不同类型。因此,如果您给 String
一个 MyProtocol
扩展名,如下所示:
extension String: MyProtocol {
func getValue() -> String {
return self
}
}
您实际上可以用混合类型初始化一个 Container
:
let container = Container(1, 4.2, "no kidding, this works")
[警告 - 我正在在线 Playground 之一中对此进行测试。我还没能在 Xcode 中测试它...]
编辑:
如果您仍然希望 Container
是通用的并且只包含一种类型的对象,您可以通过使它符合它自己的协议(protocol)来实现:
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 中的泛型数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29796654/
我是一名优秀的程序员,十分优秀!