Я не уверен, что вы подразумеваете под "типом назначения" и "типом источника", но я не вижу никаких проблем.
Если у вас есть Int
, вы можете назначить его набыть Long
.Это нормально, потому что диапазон Int
является подмножеством диапазона Long
.Вы не можете передать Long
, когда ожидаете Int
, потому что Long
имеет больший диапазон и, следовательно, может генерировать недопустимые значения Int
.И ответ о to
методах дан в вашем другом вопросе .
Рассматривая ваши дела:
var l:Long = 0 // fine because Int up-casts to Long
var l:Long = 0.toInt // fine because Int up-casts to Long
for (i:Long <- 0 to 1000000000L) { } // bad because...
0 to 1000000000L // bad because RichInt.to doesn't accept a Long argument
for (i <- 0L to 1000000000L) { } // fine because...
0L to 1000000000L // fine because RichLong.to accepts a Long argument, and produces a Range of Longs
Случаи в ваших for
примерах имеютничего общего с for
.Это связано только с тем, что вы вызываете метод to
.Объяснение:
0 to 1000000000L
является синтаксическим сахаром для 0.to(1000000000L)
, поскольку to
- это всего лишь метод.Когда вы звоните to
на Int
, происходит неявное преобразование в RichInt
, поэтому вы действительно звоните (new scala.runtime.RichInt(0)).to(1000000000L)
.Но, поскольку метод RichInt
to
принимает только аргумент Int
, передача Long
(то есть 1000000000L
) недопустима, поскольку Long
нельзя привести к Int
(так как он можетсодержат значения, выходящие за пределы диапазона Int
.
0L to 1000000000L
- синтаксический сахар, опять же, для 0L.to(1000000000L)
. Но теперь, поскольку метод to
вызывается для Long
неявное преобразование в RichLong
: (new scala.runtime.RichLong(0L)).to(1000000L)
. И поскольку метод RichLong
to
принимает Long
в качестве параметра, то все в порядке, потому что это то, что вы ему даете.
РЕДАКТИРОВАТЬ на основании ваших комментариев:
Кажется, что ваше замешательство здесь проистекает из вашей уверенности в том, что =
и to
должны работать одинаково.нет и не должно. Оператор присваивания, =
, является очень специальным ключевым словом в Scala (и любом языке), тогда как to
вовсе не является ключевым словом - это просто метод, который может быть найден в обоих RichInt
и RichLong
.
Тем не менее, по-прежнему нет противоречий. Вот почему:
Scala aПозволяет автоматически кастовать вверх , но не вниз .Причина этого очень проста: если B является разновидностью A, то B может заменить A без страха.Обратное неверно.
Предположим, у вас есть два класса:
class A
class B extends A
val a: A = null
val b: B = null
Итак, подумайте о назначениях:
val x: A = b // fine, since B is a subtype of A, so b *is* an A
val x: B = a // error, since As aren't necessarily Bs
Не давайте смотреть на вызовы функций:
def f(x: A) {} // only accept As
f(b) // fine, because a B *is* an A
def g(x: B) {} // only accept Bs
g(a) // error, because As aren't necessarily Bs
Итак, вы можете видеть, как для операторов присваивания, так и для функций, вы можете заменить подтип его супертипом.Если вы думаете о Int
как о Long
(с более ограниченным диапазоном), то это совершенно аналогично.Теперь, поскольку методы в значительной степени являются просто функциями, сидящими в классе, мы ожидаем, что поведение будет таким же в отношении аргументов.
Итак, подумайте о том, что вы просите, когда говорите, что RichInt.to(Int)
должен быть в состоянии принять Long
.Это будет означать, что Scala выполнит некоторое автоматическое и безопасное преобразование из Long
в Int
, что не имеет смысла.
В заключение: если ваша настоящая проблема заключается в том, что вы просто думаете, что RichInt
должноесть метод to(Long)
, тогда, я думаю, это то, на что жаловаться дизайнерам языков.Но они, вероятно, просто скажут вам использовать .toLong
и продолжить свою жизнь.