2015-07-24 18 views
4

лестницу Рассмотрим следующую иерархию:Верхняя и нижняя граница типа

class C1 
class C2 extends C1 
class C3 extends C2 
class C4 extends C3 

Я хочу, чтобы написать функцию, которая просто принимает Типы C2 и C3. Для этого я подумал следующее:

def f [C >: C3 <: C2](c :C) = 0 

Я бы ожидать следующее поведение

f(new C1) //doesn't compile, ok 
f(new C2) //compiles, ok 
f(new C3) //compiles, ok 
f(new C4) // !!! Compiles, and it shouldn't 

Проблема заключается при вызове его с C4, что я не хочу, чтобы позволить, но компилятор принимает. Я понимаю, что C4 <: C2 верен и что C4 можно увидеть как C3. Но при указании привязки [C >: C3 <: C2] я ожидал бы, что компилятор найдет C, который будет уважать обе границы одновременно, а не один за другим.

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

Редактировать: из ответов я понял, что моя презумпция неверна. C4 всегда выполняет C >: C3, поэтому обе границы действительно соблюдаются. Путь для моего использования - C3 <:< C.

ответ

10

Статически, да. Это довольно просто, чтобы ввести это ограничение:

def f[C <: C2](c: C)(implicit ev: C3 <:< C) = 0 

f(new C4) не компилировать в настоящее время.

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

val c: C3 = new C4 
f(c) 

Здесь переменная c имеет статический тип C3, который проходит любые проверки типов компилятором, но это на самом деле C4 во время выполнения.

Во время выполнения вы можете, конечно, проверить тип с помощью отражения или полиморфизм и бросить ошибки или вернуть Failure(...) или None

4

Я обнаружил, что объяснение от another stackoverflow question очень полезно:

S>: T просто означает, что если вы передаете типа S, которая равна Т или его родителем, то S будет использоваться. Если вы передадите тип, который является подуровнем для T, тогда будет использоваться T.

Так что в вашем примере все, но сначала следует скомпилировать. Следующий пример иллюстрирует смысл, что: Давайте пересмотреть п:

def f[U >: C3 <: C2](c: U) = c 

, а затем:

val a2 = f(new C2) 
val a3 = f(new C3) 
val a4 = f(new C4) 
List[C2](a2, a3, a4) //compiles 
List[C3](a3, a4) //compiles 
List[C4](a4) //does not cause a4 is C3 

Надежда, что помогает.

Смежные вопросы