![](/img/trans.png)
[英]How to call a static method of a generic type conforming to a protocol in Swift
[英]How to specialize protocol method on Swift Generic Type?
struct Point<T> {
var x: T
var y: T
}
extension Point: CustomStringConvertible {
var description: String {
return "\(x), \(y)"
}
}
// error: Conflicting conformance of 'Point<T>' to protocol 'CustomStringConvertible'; there cannot be more than one conformance, even with different conditional bounds
extension Point: CustomStringConvertible where T == Double{
var description: String {
return String(format: "%.3f, %.3f", x, y)
}
}
print(Point(x: 1, y: 2)) // output: 1, 2
print(Point(x: Double(1.111111), y: Double(2.222222))) // expected output: 1.111, 2.222
如何专门化 CustomStringConvertible.description: Double
类型的CustomStringConvertible.description: String
方法?
编译错误显示我不能两次扩展相同的协议。
试验 1:如果我删除了扩展语法: CustomStringConvertible
,它会编译。 但是Point<Double>.description
在调用print(Point<Double>(...))
时不会被调用。
Trail 2:如果我在第一个扩展名处添加where T == Int
,则会显示相同的编译错误。
在 Swift 中专门扩展方法的正确方法是什么?
Swift 没有与 C++ 相同的专业化概念。 请在此处查看我最近的答案,该答案解释了与 C++ 模板编程的一些差异。
另一方面,协议特化只是静态分派的,所以即使你的代码被允许,它们也不会按照你想要的方式工作。 请在此处查看此答案。
Swift 依赖于一种更传统的面向对象的方法,该方法的特点是通过协议(这在 C++ 中不常见)明确说明合同。
您希望 T 根据您的规则可转换为字符串。 所以为此定义一个协议:
protocol PointStringConvertible {
var pointString: String { get }
}
struct Point<T: PointStringConvertible> {
var x: T
var y: T
}
现在为 Double 实现 PointStringConvertible:
extension Double: PointStringConvertible {
var pointString: String {
String(format: "%.3f", self)
}
}
在 Point 中使用您的新协议:
extension Point: CustomStringConvertible {
var description: String {
"\(x.pointString), \(y.pointString)"
}
}
它会起作用:
print(Point(x: 12, y: 43))
打印12.000, 43.000
。
但是,这不适用于不符合您的协议的类型:
print(Point(x: true, y: false))
会出错。 在我看来,这很有意义。
您可以扩展所有符合 CustomStringConvertible 的类型,以便为其他类型轻松实现 PointStringConvertible:
extension PointStringConvertible where Self: CustomStringConvertible {
var pointString: String {
description
}
}
extension Bool: PointStringConvertible {}
但是当然,这仍然需要声明一致性,这不是一件坏事。 如果你不喜欢这样,你仍然可以这样做:
struct Point<T> {
var x: T
var y: T
}
extension Double: PointStringConvertible {
var pointString: String {
String(format: "A double %.3f", self)
}
}
extension Point: CustomStringConvertible {
private func pointString(for val: T) -> String {
(val as? PointStringConvertible)?.pointString ?? "\(val)"
}
var description: String {
"\(pointString(for: x)), \(pointString(for: y))"
}
}
print(Point(x: 12.0, y: 43.0))
print(Point(x: true, y: false))
给予:
A double 12.000, A double 43.000
true, false
这是否是好的设计是另一个问题。 请注意,您当然也可以简单地切换 T 的类型:
struct Point<T> {
var x: T
var y: T
}
extension Point: CustomStringConvertible {
private func pointString(for val: T) -> String {
switch val {
case let double as Double:
return String(format: "A double %.3f", double)
default:
return "\(val)"
}
}
var description: String {
"\(pointString(for: x)), \(pointString(for: y))"
}
}
print(Point(x: 12.0, y: 43.0))
print(Point(x: true, y: false))
但这可能构成了对 Double in Point 的了解。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.