问题
This doesn't compile because Initializer 'init(_:)' requires that 'Number' conform to 'BinaryInteger'
struct Percentage<Number: Numeric> {
let value: Number
let total: Number
var percentage: Double {
Double(value) / Double(total)
}
}
Does anyone have a nice solution?
To give some context to the problem from real life: I'm coding a SwiftUI app, that has a CircularProgress-view. I would like to use the same CircularProgress-view with different number types and to be able to show the current value in proportion to min and max. To do that, I need to solve the problem above.
回答1:
The main issue is that Numeric doesn't support generic divisions. One possible solution is to provide multiple generic methods to support different protocols (Integer/FloatingPoint) and Decimal as well:
extension Decimal {
var number: NSDecimalNumber { self as NSDecimalNumber }
var double: Double { number.doubleValue }
}
struct Percentage<T: Numeric> {
let value: T
let total: T
func percentage<F: BinaryFloatingPoint>() -> F where T: BinaryFloatingPoint {
F(value) / F(total)
}
func percentage<F: BinaryFloatingPoint>() -> F where T: BinaryInteger {
F(value) / F(total)
}
func percentage<F: BinaryFloatingPoint>() -> F where T == Decimal {
F(value.double) / F(total.double)
}
func percentage() -> Decimal where T == Decimal {
value / total
}
}
let percentageInt = Percentage<Int>(value: 10, total: 100)
let result1: Double = percentageInt.percentage() // 0.1
let percentageDouble = Percentage<Double>(value: 10, total: 100)
let result2: Double = percentageDouble.percentage() // 0.1
let result3: CGFloat = percentageDouble.percentage() // 0.1
let percentageDecimal = Percentage<Decimal>(value: 10, total: 100)
let result4 = percentageDecimal.percentage() // 0.1 decimal
let result5: Double = percentageDecimal.percentage() // 0.1
回答2:
You can create extensions on Percentage
where you restrict Number
to BinaryInteger
and FloatingPoint
to be able to use the /
operator.
struct Percentage<Number: Numeric> {
let value: Number
let total: Number
}
extension Percentage where Number: BinaryInteger {
var percentage: Double {
Double(value) / Double(total)
}
}
extension Percentage where Number: FloatingPoint {
var percentage: Number {
value / total
}
}
Percentage(value: 15, total: 60).percentage // 25.0
Percentage(value: 1.5, total: 3.0).percentage // 50.0
来源:https://stackoverflow.com/questions/65737343/how-can-you-create-a-generic-struct-for-numeric-numbers-that-can-calculate-a-per