Возвращаемый класс, расширяющий общую черту в Scala

Скала код:

trait Converter[S, T] {
  def convert(source: S): T
}

class StringDuplicatorConverter extends Converter[Integer, String] {
  override def convert(source: Integer): String = {
    source.toString + source.toString
  }
}

// whatever, the point is to show potentially many 'converters'
// from Integer (for example) to something
class SomeOtherConverter extends Converter[Integer, User] {
  override def convert(source: Integer): User = {
    User(source)
  }
}

trait ConverterProvider {
  def getConverter[N]: Converter[Integer, N]
}

class MyClass extends ConverterProvider {
  override def getConverter[N]: Converter[Integer, N] = {
    new StringDuplicatorConverter()
  }
}

дает

Error:(17, 5) type mismatch;
 found   : StringDuplicatorConverter
 required: Converter[Integer,N]
    new StringDuplicatorConverter()

2 ответа

Решение

Это может быть то, что вы действительно хотите для каждого ConverterProvider предоставить конвертер для определенного типа (в противном случае определение MyClass не имеет особого смысла: он должен возвращать разные конвертеры для разных N, не всегда StringDuplicatorConverter). Если это так, правильное определение

trait ConverterProvider[N] {
  def getConverter: Converter[Integer, N]
}

class MyClass extends ConverterProvider[String] {
  override def getConverter: Converter[Integer, String] = {
    new StringDuplicatorConverter()
  }
}

Да. Вызов getConverter[N] должен вернуть что-то типа Converter[Integer,N] но StringDuplicatorConverter это тип Converter[Integer,String], поскольку N не ограничивается Stringи, следовательно, они разных типов, это не скомпилируется.

Если компилятору дали некоторую гарантию, что N это, или супер-тип, String тогда это будет работать. Это можно сделать, сделав возвращаемый тип ковариантным...

trait Converter[S, +T] { ...

... а затем определяя getConverterи переопределить, вот так:

def getConverter[N >: String]: Converter[Integer, N]

Теперь он компилируется и, кажется, работает.

val mc = new MyClass
mc.getConverter.convert(7)  // res0: String = 77
Другие вопросы по тегам