У меня есть структура Vector:
struct Vector{
var X : Measurement<Dimension>
var Y : Measurement<Dimension>
var Z : Measurement<Dimension>
...
И я создаю новый объект, например:
let test = Measurement(value: 1.5, unit: UnitLength.inches) as Measurement<Dimension>
var lVector = Vector(x: Measurement(value: 10, unit: UnitLength.meters), y: test, z: Measurement(value: 10, unit: UnitLength.meters))
Все работает нормально. Но если попытаться использовать переменную из другого класса, я получил ошибку: «Невозможно преобразовать значение типа «Измерение» в тип «Измерение» при принуждении»
final class SettingsManager{
...
var test = Measurement(value: 1.5, unit: UnitLength.inches)
... }
class Calculator {
...
let test = SettingsManager.shared.test as Measurement<Dimension>
var lVector = Vector(x: Measurement(value: 10, unit: UnitLength.meters), y: test, z: Measurement(value: 10, unit: UnitLength.meters))
Я пробовал "как!" и получил
Cast from 'Measurement<UnitLength>'
to unrelated type 'Measurement<Dimension>'
always fails
Та же самая переменная, объявленная в этом классе, отлично работает, как я показал выше. Что я сделал не так?
3 ответа
Measurement<UnitLength>
не является разновидностью Measurement<Dimension>
. Это несвязанные типы. Работает только здесь:
let test = Measurement(value: 1.5, unit: UnitLength.inches) as Measurement<Dimension>
var lVector = Vector(x: Measurement(value: 10, unit: UnitLength.meters), y: test, z: Measurement(value: 10, unit: UnitLength.meters))
Потому что вызовы Measurement(...)
здесь фактически создают Measurement<Dimension>
, поскольку это то, что ожидается на месте вызова. as Measurement<Dimension>
сообщает, что вам нужен Measurement<Dimension>
, а тип параметра x
и z
также Measurement<Dimension>
. Алгоритм определения типа достаточно умен, чтобы понять, что вы также должны иметь в виду Measurement<Dimension>(...)
.
Measurement<Dimension>.init
принимает Dimension
в качестве второго параметра, а UnitLength
является его подтипом, поэтому здесь нет проблем.
С другой стороны, в SettingsManager
вы объявили test
следующим образом:
var test = Measurement(value: 1.5, unit: UnitLength.inches)
Нигде здесь вы не упомянули Measurement<Dimension>
, поэтому алгоритм вывода типа просто использует второй параметр, чтобы сделать вывод, что вы должны иметь в виду Measurement<UnitLength>
, и поэтому тип test
равен Measurement<UnitLength>
.
Если вы просто добавите as Measurement<Dimension>
var test = Measurement(value: 1.5, unit: UnitLength.inches) as Measurement<Dimension>
Он должен работать.
Однако не будет ли разумнее, если все три компонента вектора будут иметь один и тот же тип единиц измерения?
struct Vector<T: Dimension>{
var X : Measurement<T>
var Y : Measurement<T>
var Z : Measurement<T>
}
Это просто чтобы положить конец вопросу о том, почему это законно:
let test = Measurement(value: 1.5, unit: UnitLength.inches) as Measurement<Dimension>
var lVector = Vector(x: Measurement(value: 10, unit: UnitLength.meters), y: test, z: Measurement(value: 10, unit: UnitLength.meters))
Это даже не должно быть вопросом; это просто нормальный принцип замены. Возьмем более простой способ выразить это. Что, если вы не бросаете?
let test = Measurement(value: 1.5, unit: UnitLength.inches)
Тогда test
выводится как Measurement<UnitLength>
. Теперь бросим:
let test: Measurement<Dimension> = Measurement(value: 1.5, unit: UnitLength.inches)
Это законно. Почему? Это нет, потому что Measurement<UnitLength>
является подтипом Measurement<Dimension>
. Это не так! Это потому, что UnitLength является подтипом Dimension. Это как если бы вы сказали
let test = Measurement(value: 1.5, unit: UnitLength.inches as Dimension)
Ты видишь? На самом деле вы не преобразовали Measurement<UnitLength>
в Measurement<Dimension>
; это невозможно. Вы разыгрываете UnitLength до Dimension, что вполне возможно. Это ничем не отличается от того, если бы вы сказали
let test2: Dimension = UnitLength.inches
Вы всегда можете заменить подтип там, где ожидается супертип. Сложность исходного вопроса заключается в том, что Measurement<UnitLength>
не является подтипом Measurement<Dimension>
(поскольку дженерики Swift не являются автоматически ковариантными по отношению к их параметризованному типу).
Использовать
var test : Measurement<Dimension> = Measurement(value: 1.5, unit: UnitLength.inches)
Похожие вопросы
Новые вопросы
ios
iOS - мобильная операционная система, работающая на Apple iPhone, iPod touch и iPad. Используйте этот тег [ios] для вопросов, связанных с программированием на платформе iOS. Используйте связанные теги [target-c] и [swift] для проблем, характерных для этих языков программирования.
let test = Measurement(value: 1.5, unit: UnitLength.inches) as Measurement<Dimension>
работает. Думаю, я бы расценил это как ошибку в языке.Measurement<UnitLength>
не являетсяMeasurement<Dimension>
, но UnitLength, безусловно, является измерением. Ты видишь?