Ошибка Scala при реализации абстрактного метода с параметром типа

Короче говоря, это работает:

object Main {
  def main(args: Array[String]) {
    trait T1[T] {
      def f1(a: T): Double
    }

    val ea1 = new T1[List[String]] {
      def f1(a: List[String]): Double = a.length
    }
  }
}

Но это не скомпилируется:

object Main {
  def main(args: Array[String]) {
    trait T1 {
      def f1[T](a: T): Double
    }

    val ea1 = new T1 {
      def f1(a: List[String]): Double = a.length
    }
  }
}

object creation impossible, since method f1 in trait T1 of type [T](a: T)Double is not defined
    val ea1 = new T1 {
              ^

Похоже, что метод не учитывается из-за параметра типа в методе.

Как я могу добиться этого без использования параметров типа признака или абстрактных типов признака ?! TIA!


person Vincenzo Maggio    schedule 29.08.2013    source источник


Ответы (2)


Вы можете определить type T, чтобы избавиться от параметров типа черты и выполнить то же самое, что и ..

    trait T1 {
      type T
      def f1(a: T): Double
    }

    val ea1 = new T1 {
       type T = List[String]
       def f1(a: T): Double = a.length
    }                                            

    ea1.f1(List("1","2"))  
    // res0: Double = 2.0
person Shrey    schedule 29.08.2013
comment
Хотя это хорошее решение, я заявил, что мне не нужны параметры типа признака, я бы хотел, чтобы в функции выводился тип T. Типажные абстрактные типы в простых случаях, подобных этому, работают как обычные параметры типа класса ... - person Vincenzo Maggio; 29.08.2013
comment
Что ж, с помощью небольшого обходного пути мне удалось получить то, что я хотел, благодаря вашему ответу, я приму его ... - person Vincenzo Maggio; 19.09.2013

Существует "приватная опция" -Yinfer-argument-types, которая позволяет вам:

scala> trait T { def f(i: Int) }
defined trait T

scala> new T { def f(i) = 2 * i }
res1: T = $anon$1@7915e83

Вы просите вариант, который будет эквивалентен:

scala> new T { def f() = 2 * i }

кроме параметров типа вместо параметров значения.

Я не уверен, какой будет семантика в вашем примере. У метода есть параметр типа, но бросить, если это не тот тип, который я ожидал?

Изменить: может быть, вы имеете в виду это:

scala> trait T { def f[ @specialized(Int) A](a: A): A = ??? }
defined trait T

scala> new T { def f(i: Int) = 2*i }
res0: T{def f(i: Int): Int} = $anon$1@50844aeb

scala> res7 f 7
warning: there were 1 feature warning(s); re-run with -feature for details
res8: Int = 14

В специализированном методе нет параметра типа.

Обновление: вероятно, это первое появление пропущенных трассировок стека REPL на SO:

scala> res7 f "hi!"
warning: there were 1 feature warning(s); re-run with -feature for details
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:229)
  at $anon$1.f(<console>:9)
person som-snytt    schedule 29.08.2013
comment
Не знал о типах аргументов -Yinfer, спасибо! К сожалению, предоставление параметра типа при создании экземпляра признака - это именно то, чего я бы хотел избежать, учитывая, что я хотел бы, чтобы клиент реализовал функцию без указания параметра типа (а затем использовал границы представления для дисперсии / контравариантности). Мне это начинает казаться слишком большим для вывода типа Scala ... - person Vincenzo Maggio; 29.08.2013
comment
@VincenzoMaggio Специализация - это то, что вы хотите. На мой вопрос, что делать, если это не тот тип, который вы ожидаете, есть ответ: вызовите другой метод. По крайней мере, специализация - единственный способ разобраться в вашем вопросе. - person som-snytt; 29.08.2013
comment
Разве специализация не только для примитивных типов ?! - person Vincenzo Maggio; 29.08.2013
comment
@VincenzoMaggio Да, я размышлял. Вы можете выполнить отправку самостоятельно, динамически или с помощью макроса, от f[A: TypeTag](a: A) до любой доступной реализации. - person som-snytt; 30.08.2013