Следующая не может скомпилировать с Scala 2.11.4:Озадаченный типа несоответствия при применении Scala FUNCTION1
trait Test {
type A
type F = Function1[A, String]
}
trait Util[T <: Test] {
def compute1(f: T#A => String, a: T#A): String = f(a)
def compute2(f: T#F, a: T#A): String = f(a)
// ^
}
Существует ошибка компиляции на аргумент вызова (^):
type mismatch;
found : a.type (with underlying type T#A) required: _3317.A
Я ожидал, что два аргумента f в compute1 и compute2 будут иметь один и тот же тип; очевидно нет.
Что происходит?
Как @Eugene и @ Zim-Zam ответили, проблема здесь связана с зависимыми от типа Scala типами. На основании их предложения, я придумал несколько вариантов:
trait Test {
type A
type Fa = Function1[A, String] // original question
type Fb = Function1[Test#A, String] // Zim-Zam's suggestion
}
trait TestOps[T <: Test] {
type G = Function1[T#A, String]
}
trait Util[T <: Test] {
def compute1(f: T#A => String, a: T#A): String = f(a)
// def compute2a(f: T#Fa, a: T#A): String = f(a)
// type mismatch; found : a.type (with underlying type T#A) required: _1536.A
def compute2b(f: T#Fb, a: T#A): String = f(a)
}
trait Util1 {
def compute3a(t: Test)(f: t.Fa, a: t.A): String = f(a)
def compute3b(t: Test)(f: t.Fb, a: t.A): String = f(a)
}
trait Util2[T <: Test] { tops: TestOps[T] =>
// def compute4a(f: T#Fa, a: T#A): String = f(a)
// type mismatch; found : a.type (with underlying type T#A) required: _1642.A
def compute4b(f: T#Fb, a: T#A): String = f(a)
def compute5(f: tops.G, a: T#A): String = f(a)
}
Util сравнивает оригинальную работу с предложением @ ЗИМ-ZAM в
Util1 упражнение разницы в указании Function1 типа аргумента: A
против Test#A
Util2 упражняется в определении типа Function1 для другого признака: TestOps
Комментируя варианты, не задающие проверку, у нас осталось:
compute1
compute2b
compute3a
compute3b
compute4b
compute5
Что лучше для специализируя эти черты?
чесать различия, я сделал простое уточнение:
class U
class TestU extends Test {
override type A = U
}
class UOps extends TestOps[TestU]
Вот результаты:
trait UtilU extends Util[TestU] {
def get1(f: TestU#A => String, a: TestU#A) = compute1(f, a)
// def get2b(f: TestU#A => String, a: TestU#A) = compute2b(f, a)
// type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
}
trait UtilU1 extends Util1 {
val u = new TestU()
def get3a(f: u.A => String, a: u.A) = compute3a(u)(f, a)
// def get3b(f: u.A => String, a: u.A) = compute3b(u)(f, a)
// type mismatch;
// found : UtilU1.this.u.A ⇒ String (which expands to) A.U ⇒ String
// required: UtilU1.this.u.Fb (which expands to) A.Test#A ⇒ String
}
class UtilU2 extends Util2[TestU] with TestOps[TestU] {
// def get4b(f: TestU#A => String, a: TestU#A) = compute4b(f, a)
// type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
def get5(f: TestU#A => String, a: TestU#A) = compute5(f, a)
}
Итак, мы оставили только три разумных вариации:
compute1
(нет псевдонима функции1) compute3a
compute5
Для наложения типов FUNCTION1, мы остались только 2 альтернативы: compute3a
и compute5
Каковы надлежащие способы, чтобы описать различия между ними?
другой вариант - определить F внутри Util –
Спасибо @ Zim-Zam за предложение. Однако этот подход вызывает проблемы при определении специализаций теста признаков, поскольку типы аргументов функции являются противоположными вариантами в Scala. –