Я не могу убедить компилятор вызвать random(in:)
для общего типа BinaryFloatingPoint таким же образом, как я могу вызвать его для определенного типа, например Double
.
Код (случайный характерен для Double,random2 - это попытка использования универсальной функции):
import SceneKit
extension SCNVector3 {
public static func random(_ xrange: ClosedRange<Double>,
_ yrange: ClosedRange<Double>,
_ zrange: ClosedRange<Double>)
-> SCNVector3 {
let x = ClosedRange<Double>.Element.random(in: xrange)
let y = ClosedRange<Double>.Element.random(in: yrange)
let z = ClosedRange<Double>.Element.random(in: zrange)
return SCNVector3(x, y, z)
}
public static func random2<T: BinaryFloatingPoint>(_ xrange: ClosedRange<T>,
_ yrange: ClosedRange<T>,
_ zrange: ClosedRange<T>)
-> SCNVector3 {
let x = ClosedRange<T>.Element.random(in: xrange)
let y = ClosedRange<T>.Element.random(in: yrange)
let z = ClosedRange<T>.Element.random(in: zrange)
return SCNVector3(x, y, z)
}
}
Я получаю следующую жалобу компилятора (сокращенно в первую очередь):
/SwiftMath/Sources/SwiftMath/SCNVector3.swift:35:17: error: ambiguous reference to member 'random(in:using:)'
let x = ClosedRange<T>.Element.random(in: ClosedRange<T>(xrange))
^~~~~~~~~~~~~~~~~~~~~~
Swift.BinaryFloatingPoint:2:24: note: found this candidate
public static func random<T>(in range: Range<Self>, using generator: inout T) -> Self where T : RandomNumberGenerator
^
Swift.BinaryFloatingPoint:3:24: note: found this candidate
public static func random(in range: Range<Self>) -> Self
^
Swift.BinaryFloatingPoint:2:24: note: found this candidate
public static func random<T>(in range: ClosedRange<Self>, using generator: inout T) -> Self where T : RandomNumberGenerator
^
Swift.BinaryFloatingPoint:3:24: note: found this candidate
public static func random(in range: ClosedRange<Self>) -> Self
Для моего неподготовленного глаза кажется, что естьтолько одно совпадение:
public static func random(in range: ClosedRange<Self>) -> Self
Перегрузки, которые принимают RandomNumberGenerator
, не должны учитываться.
Есть ли какое-то преобразование между ClosedRange
и Range
, которое заставляет обе эти перегрузки выглядеть возможным?
Для справки, метод random(in:)
для BinaryFloatingPoint
можно найти здесь: SwiftDocs .
Обновление (с предварительным ответом на основе комментария от @dan):
Первоначальная проблема заключалась в том, что протокол BinaryFloatingPoint
предоставил только методы random
для подмножества типов.Это не было очевидно из ошибки компилятора.
Устраняя эту проблему и пытаясь обнаружить все типы, которые имеют необходимые методы random
, лучшее, что я могу придумать, - это два разных набора общих ограничений для условий.Прежде чем остановиться на этом как на ответе, я хотел бы выяснить, можно ли объединить ограничения в некотором вопросе, чтобы я мог просто написать одно расширение для ClosedRange и один новый метод для SCNVector3 вместо пар методов для каждого.
extension ClosedRange where Element: BinaryFloatingPoint,
Element.RawSignificand: FixedWidthInteger {
public func random() -> Element {
return Element.random(in: self)
}
}
extension ClosedRange where Element: FixedWidthInteger {
public func random() -> Element {
return Element.random(in: self)
}
}
/// SCNVector3 Operators
///
/// Random
extension SCNVector3 {
public init<T:BinaryFloatingPoint>(_ x: T, _ y: T, _ z: T) {
self.init()
self.x = CGFloat(x)
self.y = CGFloat(y)
self.z = CGFloat(z)
}
public init<T:FixedWidthInteger>(_ x: T, _ y: T, _ z: T) {
self.init()
self.x = CGFloat(x)
self.y = CGFloat(y)
self.z = CGFloat(z)
}
public static func random<T: BinaryFloatingPoint>(_ xrange: ClosedRange<T>,
_ yrange: ClosedRange<T>,
_ zrange: ClosedRange<T>)
-> SCNVector3 where T.RawSignificand: FixedWidthInteger {
let x = ClosedRange<T>.Element.random(in: xrange)
let y = ClosedRange<T>.Element.random(in: yrange)
let z = ClosedRange<T>.Element.random(in: zrange)
return SCNVector3(x, y, z)
}
public static func random<T: FixedWidthInteger>(_ xrange: ClosedRange<T>,
_ yrange: ClosedRange<T>,
_ zrange: ClosedRange<T>)
-> SCNVector3 {
let x = ClosedRange<T>.Element.random(in: xrange)
let y = ClosedRange<T>.Element.random(in: yrange)
let z = ClosedRange<T>.Element.random(in: zrange)
return SCNVector3(x, y, z)
}
}