Swift 4 - ошибка компилятора при случайном вызове универсального типа BinaryFloatingPoint - PullRequest
0 голосов
/ 02 октября 2018

Я не могу убедить компилятор вызвать 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)
    }
}
...