Swift: умножить две цифры - PullRequest
       8

Swift: умножить две цифры

0 голосов
/ 30 марта 2020
protocol DArray: Sequence where Element: Numeric {
    var elements: [Element] { get set }
    subscript(index: Int) -> Element { get set }
    static func *(lhs: Self, rhs: Self) -> Self
}

struct Vector<Element: Numeric>: DArray {
    var elements: [Element]

    init(_ elements: [Element] = []) {
        self.elements = elements
    }

    ...

    static func *<T: DArray>(lhs: Self, rhs: T) -> Self {
        var v = lhs
        var result: Self
        for (i, element) in rhs.enumerated() {
            let e = v[i]
            let r = element * e
            // Cannot convert value of type 'Element' (generic parameter of generic struct 'Vector') to expected argument type 'T.Element' (associated type of protocol 'Sequence')
        }
        return result
    }
}

Для протокола Numeric документация гласит:

Протокол Numeri c обеспечивает подходящую основу для арифметики c для скалярных значений, таких как целые и плавающие числа Вы можете написать обобщенные c методы, которые работают с любым типом нумерации c в стандартной библиотеке, используя протокол Numeri c в качестве ограничения обобщенного c.

Поэтому я выбрал Протокол Numeri c в качестве общего ограничения c для типа Element, а также для T.Element. Хотя и e, и element соответствуют протоколу Numeric, я не могу умножить их (получая сообщение об ошибке: Невозможно преобразовать значение типа 'Элемент' (параметр generi c, параметр generi c struct 'Vector') к ожидаемому типу аргумента 'T.Element' (связанный тип протокола 'Sequence') ). Как мне это сделать?

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Как упомянул @Sweeper, вы можете умножать только те же самые Numeric s.

Таким образом, вы должны указать это в своей функции, используя выражение where:

static func * <T: DArray> (lhs: Vector<Element>, rhs: T) -> Vector<Element> where T.Element == Element {
    let result = zip(lhs, rhs).map { lhs, rhs in
        lhs * rhs
    }
    return Vector(result)
}
0 голосов
/ 30 марта 2020

Поскольку умножение является коммутативным, нет смысла определять тип вывода * как один из типов операндов. Вместо этого вы можете разрешить инициализацию всех DArray с их элементами.

protocol DArray: Sequence where Element: Numeric {
  var elements: [Element] { get set }
  init<Elements: Sequence>(_: Elements) where Elements.Element == Element
}

extension Vector {
  init<Elements: Sequence>(_ elements: Elements) where Elements.Element == Element {
    self.init( Array(elements) )
  }
}

И затем определить оператор следующим образом:

extension DArray {
  static func * <Parameter1: DArray, Output: DArray>(
    dArray0: Self, dArray1: Parameter1
  ) -> Output
  where Parameter1.Element == Element, Output.Element == Element {
    multiply(dArray0, dArray1)
  }

  static func * (dArray0: Self, dArray1: Self) -> Self {
    multiply(dArray0, dArray1)
  }

  private static func multiply<Parameter0: DArray, Parameter1: DArray, Output: DArray>(
    _ dArray0: Parameter0, _ dArray1: Parameter1
  ) -> Output
  where Parameter0.Element == Parameter1.Element, Parameter1.Element == Output.Element {
    .init( zip(dArray0, dArray1).map(*) )
  }
}

Таким образом, вы можете явным образом введите результат, как вам угодно, и получите перегрузку для случая, когда имеет смысл использовать неявную типизацию.

struct ?: DArray, IteratorProtocol {
  mutating func next() -> Int? { nil }

  var elements: [Element] = []

  init<Elements: Sequence>(_ elements: Elements) where Elements.Element == Element { }
}


( Vector() * ?([]) ) as Vector
( Vector() * ?([]) ) as ?
( ?([]) * Vector() ) as Vector
( ?([]) * Vector() ) as ?

let vector: Vector = ( Vector() * ?([]) )
let ?: ? = ( ?([]) * Vector() )

Vector([1]) * Vector()
...