Соответствие шаблону типа, почему переменная является обязательной - PullRequest
2 голосов
/ 05 июля 2019

Я читаю "Scala for Impatient 2nd", раздел 14.4, где я запутался в контексте:

Вы можете сопоставить тип выражения, например:

obj match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
}

Когда вы сопоставляете тип, вы должны указать имя переменной.В противном случае вы сопоставляете объект:

obj match {
   case _:BigInt => Int.MaxValue // Matches any object of type BigInt
   case BigInt => -1 // Matches the BigInt object of type Class
}

Меня смущает, как понимать obj, который запрашивается как expression: если я проверяю, как показано ниже:

val x = 121
val obj : Any = x
obj == 121 // true

obj match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
} // res133: Int = 121

Однако, если я просто присваиваю целочисленное значение для obj, компилятор выдает ошибку:

val obj2 = 121
obj2 == 121 // true

obj2 match {
   case x:Int => x
   case s:String => Integer.parseInt(s)
   case _:BigInt => Int.MaxValue
   case _ => 0
} // <console>:22: error : scrutinee is incompatible with pattern type;
found : String
required : Int
    case s : String => Integer.parseInt(s)
             ^    
<console>:23: error : scrutinee is incompatible with pattern type;
found : BigInt
required : Int
    case _ : BigInt => Int.MaxValue
             ^      

Единственным отличием является первый пример, которому я назначил obj другой переменной, тогда как последний примерЯ назначил obj целочисленным значением.Почему в последнем примере возникает ошибка компиляции?

Обновление вопроса : я понимаю, что "компилятор знает, что obj2 - это Int", однако я подумал, что именно это match выражение работает для, i, e, потому что obj2 равно Int и соответствует первому match предложению case x:Int => x, таким образом, совпадение успешно и все выражение совпадения завершено.Я подумал, что это должно быть точно так же, как в предыдущем примере, единственное отличие состоит в том, что две переменные имеют тип Any и Int, но все они соответствуют первому предложению соответствия, и обе они должны быть правильно скомпилированы.

Из этой книги Раздел 14.4 «В Scala это (сопоставление с шаблоном типа) предпочтительнее, чем с использованием оператора isInstanceOf», я думал, что использование шаблонов типов - это способ определения типа объекта.Если мы знаем тип объекта, для чего используется «тип шаблона»?

Второй вопрос: я запутался в контексте ниже.Как понять "объект типа BigInt" против "объекта BigInt типа Class"?"type Class" связан с общим понятием / отражением Java?

obj match {
   case _:BigInt => Int.MaxValue // Matches any object of type BigInt
   case BigInt => -1 // Matches the BigInt object of type Class
}

Спасибо!

Ответы [ 3 ]

5 голосов
/ 05 июля 2019

Во втором случае компилятор знает, что obj2 равно Int, и поэтому он знает, что невозможно, чтобы совпадение для String или BigInt могло быть успешным.


Здесь существует различие между тем, что известно во время компиляции, и тем, что известно во время выполнения.У вас есть следующий код:

val x = 121
val obj: Any = x

Во время выполнения оба значения x и obj равны Int и будут соответствовать первому регистру в вашем выражении match.

Во время компиляции компилятор знает, что x равен Int, поэтому он знает, что нет смысла тестировать String или BigInt.Все, что он знает о obj, это то, что это Any, так что можно проверить String, BigInt или любой другой тип.

Теперь в этом случае ясно, что компилятор могВыясните, что obj на самом деле Int, но в общем случае это невозможно.Вместо того, чтобы иметь сложные правила вывода типов, компилятор просто использует тип, который программист дал значению, равному Any.Таким образом, предполагается, что obj может быть String или BigInt, хотя в этом случае из кода очевидно, что это не так.

3 голосов
/ 05 июля 2019

Как понимать "объект типа BigInt" против "объекта BigInt типа Class"? Связан ли «типовой класс» с концепцией обобщенного / рефлективного кода Java?

Это просто ошибка в книге. Шаблон BigInt (т.е. case BigInt => ...) соответствует объекту-компаньону , объявленному как

object BigInt { ... }

в коде. Это не типа Class; его тип записывается как BigInt.type, но это довольно редко полезно.

Так что, если вы напишите

val x: Any = BigInt

x match {
  case _: BigInt => // doesn't match
  case BigInt => // matches
}

, тогда как val x: Any = new BigInt(...) будет соответствовать первому, а не второму.

1 голос
/ 05 июля 2019

Во втором присваивании отсутствует указание типа, поэтому из-за вывода типа

val obj2 = 121

делает obj2 Int, в отличие от

val obj : Any = x

, что делает его Any.

...