Вы неправильно поняли Int with String
.Это не объединение Int и String, это пересечение, а для Int и String оно пустое.Не наборы значений, которые являются Int с набором значений, которые являются строками, но набор значений, которые имеют характеристики Int с характеристиками String тоже.Там нет таких значений.
Вы можете использовать Either[Int, String]
и иметь Map[Left(1) -> 2, Right("Hello") -> 3)
.Либо это не совсем Союз, это различаемый союз, A + B, а не AU B. Вы можете понять разницу в том, что либо [Int, Int] не то же самое, что Int.Это на самом деле изоморфно (Int, Boolean): у вас есть Int, и вы знаете, с какой стороны это тоже.Когда A и B являются дизъюнктами (как Int и String), A + B и AUB изоморфны.
Или (не для слабонервных) вы можете взглянуть на возможную кодировку объединениятипы Майлза Сабина.(Я не уверен, что вы могли бы действительно использовать это с существующим классом Map, и даже менее уверенно, чем вы должны даже пытаться, но тем не менее это делает чтение наиболее интересным).
Edit : прочитайте ваш вопрос и код слишком быстро, извините
Ваша нижняя граница Int with String
такая же, как Nothing
, поэтому Map[_ >: Int with String, Int]
, такая же, как Map[_ >: Nothing, Int]
и Nothing
подразумевается нижняя граница, это Map[_, Int]
.Ваш фактический Map
является Map[Any, Int]
.Вы могли бы добавить логический ключ, он тоже работает, несмотря на Int с String.Map[Any, Int]
может быть напечатано как Map[_, Int]
, так что ваша декларация val работает.Но ваш набор текста теряет всю информацию о типе ключа.Не зная, какой тип ключа, вы не можете ничего добавить (или извлечь) из таблицы.
UpperBound был бы не лучше, так как тогда не было бы возможных ключей.Даже первоначальное объявление val терпит неудачу.
Edit 2 : относительно if (true) Map(1 -> 2) else Map("1" -> 2)
Это не то же самое, что Map(1 -> 2, "1" -> 2)
.Это было проще, просто Map[Any, Int]
, так как Any
является более распространенным супертипом Int
и String
.
С другой стороны, Map(1 -> 2)
- это Map[Int, Int]
, а Map["1", 2]
a Map[String, Int]
.Существует проблема поиска общего супертипа для Map[Int, Int]
и Map[String, Int]
, который не находит общего супертипа для Int
и String
.
Давайте поэкспериментируем.Map
является ковариантным по второму параметру.Если вы используете Int
и String
в качестве значений, а не ключей:
if (true) Map(1 -> 2) else Map(1 -> "2")
res1: scala.collection.immutable.Map[Int, Any]
С ковариацией просто берется общий супертип всех параметров типа.
С контравариантным типом
class L[-T]
object L{def apply[T](t: T) = new L[T])
class A
class B extends A
class C
if (true) L(new A) else L(new C)
res2: L[A with C]
if (true) L(new A) else L(new B)
res3: L[B]
принимает пересечение A with C.
Когда B
является подтипом A
, A
с B
равно B
.
Теперь с неизменяемым параметром Map, когда два типа связаны
if (true) Map(new A -> 1) else Map(new B -> 1)
res4: scala.collection.immutable.Map[_ >: B <: A, Int]
Такой тип не бесполезен.Вы можете получить доступ или добавить значения с помощью клавиш типа B
.Но вы не можете получить доступ к значениям ключей A
.Так как это то, что у вас есть на реальной карте (из-за true
), неудачаЕсли вы получите доступ к keySet
, он будет набран Set[A]
.У вас есть неполная информация о типе ключей, и то, что вы можете сделать, ограничено, но это необходимое ограничение, учитывая ограниченные знания о типе карты.С Int and String
у вас есть минимальная информация, с нижней границей Any
и верхней границей, эквивалентной Nothing
.Верхняя граница Nothing делает невозможным вызов подпрограммы, которая принимает ключ в качестве параметра.Вы все еще можете получить keySet
, с типом Set[Any]
, Any
является нижней границей.