Scala конструкторы классов и абстрактные типы

Я хочу использовать абстрактный тип, а не параметр типа.

В моем конструкторе generic classes я хочу иметь параметр типа generic, но код не компилируется:

class SomeOtherClass(val s: S){
    type S
}

Ошибка компилятора scala "не найдена: type S"

Если я использую параметр типа вместо абстрактного типа, то он работает:

class SomeClass[T](val t: T){
    //...
}

Заставляет ли scala использовать параметр типа, а не абстрактный тип, если я хочу иметь общий параметр в конструкторе?

Есть ли другой способ сделать это?

Ответ 1

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

trait FooDef {
  type T
  class Foo(val x: T)
}
val ifd = new FooDef { type T = Int }
val ifoo = new ifd.Foo(5)
val sfd = new FooDef { type T = String }
val sfoo = new sfd.Foo("hi")
def intFoos(f: fd.Foo forSome { val fd: FooDef {type T = Int} }) = f.x + 1

Ответ 2

Если абстрактный тип не указан, ваш класс должен быть абстрактным. Таким образом, вам не нужен параметр вообще. Эквивалентом с абстрактным типом будет:

abstract class SomeOtherClass {
  type S
  val s: S 
}

Затем на сайте использования:

val x = new SomeOtherClass {
  type S = String
  val s = "abc"
}

Без параметра абстрактный класс здесь эквивалентен признаку. Вам лучше использовать черту, потому что она менее ограничительна (вы можете расширить только один базовый класс).

Ответ 3

Как компилятор должен знать, какой тип он должен использовать там? Либо вы должны указать тип напрямую, что не имеет смысла, либо использовать общий. Есть один способ заставить его работать, но я не думаю, что он вам поможет.

class SomeClass(s: SomeClass#S) {
  type S
}

Но поскольку SomeClass # S не определен, его экземпляр отсутствует.

Ответ 4

Может быть, вы хотите что-то вроде этого? Таким образом, вы можете иметь несколько экземпляров AbstractFooFactory, каждый из которых производит Foo с другим значением для s.

trait AbstractFooFactory {
  type S
  def makeFoo(s:S):Foo
  class Foo(val s:S) {}
}

object StringFooFactory extends AbstractFooFactory {
  override type S = String
  override def makeFoo(s:String) = new Foo(s)
}

val b = StringFooFactory.makeFoo("bar")
val s:String = b.s