我想增加我对仿制药的了解,我遇到了一个无法解决的问题。我有两种不同的类型(Int
和Double
)。两种类型都实现了函数advanced(by:)
。我想创建一个泛型函数来调用给定类型的advanced(by:)
。
这样做的好处是我可以用intAdvancedByTen(value:)
替换doubleAdvancedByTen(value:)
和genericAdvancedByTen(value:)
。
这是我的游乐场:
let myDouble: Double = 1
let myInt: Int = 2
func intAdvanceByTen(value: Int) { // Replace this function
value.advanced(by: 10)
}
func doubleAdvanceByTen(value: Int) { // ...and this function
value.advanced(by: 10)
}
protocol CanAdvance {
func advance(_ by: Any)
}
// ...with this generic function
func genericAdvanceByTen(value: CanAdvance) {
value.advance(10)
}
genericAdvanceByTen(value: myInt) // Error: Argument "Int" does not conform to expected type "CanAdvance"
如何让泛型函数知道传递的类型实现了advanced(by:)
方法?
答案 0 :(得分:1)
试试这个:
protocol CanAdvance {
// This method is intentionally designed to have the same signature as the
// methods built into Int and Double
func advanced(by: Self) -> Self
// We need this primarily for the definition of the constant 10. The built
// in `advanced` function requires the distance to be of the same type.
//
// The conversion syntax in Swift is via init:
// let aDouble = Double(anInt)
// Not the C-like cast:
// let aDouble = anInt as! Double // invalid
//
// Hence we must have a way to convert 10 to the appropriate Int or Double.
// Conveniently, both types can convert from an Int32 so we put this
// requirement in the protocol
init(_ value: Int32)
}
extension Int : CanAdvance { }
extension Double : CanAdvance { }
func genericAdvanceByTen<T: CanAdvance>(value: T) -> T {
let distance = T(10)
return value.advanced(by: distance)
}
genericAdvanceByTen(value: 2) // 12
genericAdvanceByTen(value: 3.14) // 13.14
答案 1 :(得分:1)
无需定义自己的协议 - advanced(by:)
由标准的libary&#39; Strideable
协议定义:
public protocol Strideable : Comparable {
/// A type that can represent the distance between two values of `Self`.
associatedtype Stride : SignedNumber
// ...
/// Returns a `Self` `x` such that `self.distance(to: x)` approximates `n`.
///
/// If `Stride` conforms to `Integer`, then `self.distance(to: x) == n`.
///
/// - Complexity: O(1).
public func advanced(by n: Self.Stride) -> Self
}
因此,您只想约束函数以获取Strideable
输入。
鉴于Stride
关联类型(advanced(by:)
期望作为参数)被约束为SignedNumber
,它必须符合ExpressibleByIntegerLiteral
- 这允许我们通过整数字面直接到它。
例如:
func genericAdvancedByTen<T : Strideable>(value: T) -> T {
// Utilise the fact that T.Stride is ExpressibleByIntegerLiteral.
return value.advanced(by: 10)
}
print(genericAdvancedByTen(value: 2)) // 12
print(genericAdvancedByTen(value: 3.14)) // 13.14