2016-06-03 1 views
3

При использовании экзистенциальных типов в Scala кажется, что компилятор указывает на то, что каждое использование экзистенциального объекта является другим параметром типа, даже если они на самом деле одинаковы.Несоответствие типа Scala, неспособное вывести T =: = T

Для простой надуманный пример - Учитывая следующий код

class Box[T](value:T){ 
    def get:T = value 
    def contains(check:T):Boolean = value == check 
} 

я могу сделать следующее

val b1 = new Box(1) 
b1.contains(b1.get) 

Однако при использовании экзистенциальных типов ...

val b2 : Box[_] = new Box(1) 
b2.contains(b2.get) 

Я получаю следующая ошибка (In scala 2.11.7

[error] /private/tmp/exttest/test.scala:53: type mismatch; 
[error] found : (some other)_$6(in value b2) 
[error] required: _$6(in value b2) 
[error] b2.contains(b2.get) 

Мое предположение заключалось в том, что компилятор понимает, что тот же параметр типа _$6 используется в обоих случаях, однако он, кажется, теряет следы и рассматривает их как отдельные типы.

Я принципиально недопонимаю что-то о экзистенциальных типах, или это ошибка в компиляторе Scala - и если да, то есть ли оптимальная практика для ее работы?

ответ

2

Другим решением является использование переменной модели типа, чтобы дать имя для шаблона и помочь Scala понять, что они одинаковы:

val b2 : Box[_] = new Box(1) 
b2 match { 
    case b: Box[a] => b.contains(b.get) 
} 
6

Это скорее скорее ограничение, чем ошибка.

Часто простой способ обойти это, чтобы переместить чувствительный код общего метода:

def containsSelf[T](box: Box[T]): Boolean = 
    box.contains(box.get) 

val b2 : Box[_] = new Box(1) 
containsSelf(b2) 

Или создать свой класс с членами типа вместо генерик. Это может быть немного больше шаблонного-у, но именно то, что вы хотите:

trait Box { 
    type Element 
    def get: Element 
    def contains(check: Element): Boolean 
} 
object Box { 
    type Aux[T] = Box { type Element = T } 
    def apply[T](value: T): Box.Aux[T] = 
    new Box { 
     type Element = T 
     def get = value 
     def contains(check: T) = value == check 
    } 
} 

val b2: Box = Box(1) 
b2.contains(b2.get) 
0

Я думаю, что тип связан с check в def contains(check:T):Boolean = value == check ограничивает согласование.

я получаю следующее, когда я применить обходной путь, как так:

scala> class Box[T](value:T){ 
    | def get:T = value 
    | def contains(check:X forSome { type X}):Boolean = value == check 
    | } 
warning: there was one feature warning; re-run with -feature for details 
defined class Box 

scala> val b1 = new Box(1) 
b1: Box[Int] = [email protected] 

scala> b1.contains(b1.get) 
res0: Boolean = true 

scala> val b2 : Box[_] = new Box(1) 
b2: Box[_] = [email protected] 

scala> b2.contains(b2.get) 
res1: Boolean = true 
+1

Это в значительной степени эквивалентно наличию 'def содержит (check: Any)' – ghik

+0

Хм, да, я думаю, ваше решение более надежное. –