Reputation: 1176
I've made a class with generic type T, where T should only be a numeric value (CGFloat
, Double
, Int
, etc.) and should be able to be converted to Double
. I've tried several types, like Numeric
and Equatable
, but those still cast the net too wide. When converting to Double
the type should conform to either BinaryInteger
or BinaryFloatingPoint
but I've yet to find a way to let a generic conform to either one of two types.
What I want:
class SomeClass<T:SomeNumberTypeThatAllowsConversionToDouble> {
var number: T
var doubleNumber: Double
init(number: T) {
self.number = number
self.doubleNumber = Double(number) //or some other function that converts from T to Double
}
}
What I don't want is two separate extensions to SomeClass
where one handles the BinaryInteger
case and one the BinaryFloatingPoint
case, since that would defeat the purpose of why I'm using generics in the first place.
Upvotes: 3
Views: 570
Reputation: 301
What you would like achieve is constraint T to conform to a fixed group of protocol.
It is very similar to what we have in Typescript T:number|point|size
( union type mentioned by @Dávid Pásztor )
below is my workaround in Swift.It is not that neat and maybe we can have better solution.
protocol DoubleConvertible { }
extension Int:DoubleConvertible { }
extension CGFloat:DoubleConvertible { }
extension Double:DoubleConvertible {
static func convert(_ number:DoubleConvertible) -> Double {
if let intNumber = number as? Int {
return Double(intNumber)
} else if let cgFloatNumber = number as? CGFloat {
return Double(cgFloatNumber)
} else if let doubleNumber = number as? Double{
return Double(doubleNumber)
} else {
assertionFailure()
}
}
}
import UIKit
class SomeClass<T> where T:DoubleConvertible {
var number: T
var doubleNumber: Double
init(number: T) {
self.number = number
self.doubleNumber = Double.convert(number)
}
}
print(SomeClass<Int>(number: 10).doubleNumber)
print(SomeClass<Double>(number: 10.0).doubleNumber)
print(SomeClass<CGFloat>(number: CGFloat(integerLiteral: 10)).doubleNumber)
//10.0
//10.0
//10.0
print(SomeClass<CGPoint>(number: 10).doubleNumber)
//Type 'CGPoint' does not conform to protocol 'DoubleConvertible'
Upvotes: 3