Как получить доступ к параметру типа класса в Scala

У меня есть абстрактный класс с параметризованным типом, который содержит val и метод, которые используют свой параметр типа

abstract class Foo[T](val state: T){
  def foo(arg: T){
    ...
  }
}

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

class Bar(myNumber: Int) extends Foo[Int](myNumber){
   ...
}

Я передаю экземпляр Bar другому классу, который принимает любой подкласс Foo, и я хотел бы вызвать метод foo для state, но у меня возникли проблемы:

class Baz(val f: Foo[_]){
    f.foo(f.state)
}

Это дает ошибку:

<console>:8: error: type mismatch;
 found   : Baz.this.f.state.type (with underlying type _$1)
 required: _$1
         f.foo(f.state)

Есть ли способ дать Baz информацию о параметре типа Bar, чтобы он правильно компилировался? Или это даже то, что я хочу сделать?

Изменить

Чтобы уточнить, у меня есть много классов, подобных Bar, которые расширяют Foo и предоставляют свой собственный параметр типа, состояние и реализацию foo. Я хотел бы, чтобы пользователи моей библиотеки могли передавать любой из них в Baz, не беспокоясь о параметре типа T, поскольку это всего лишь деталь реализации каждого подкласса Foo.

Поэтому я бы настоятельно предпочел не делать этого:

class Baz[T](val f: Foo[T]){
  f.foo(f.state)
}

person DLaw    schedule 25.05.2014    source источник
comment
Экзистенциалы считаются вредными. В этой ветке рассказывается, почему, и о различных решениях. что можно было бы использовать.   -  person ggovan    schedule 25.05.2014
comment
Этот вопрос отличается, потому что спрашивающий указывает тип T и хочет, чтобы экзистенциальный тип был его суперклассом. В своем вопросе я хочу полностью его игнорировать. Кроме того, я попробовал их ответ, и это не сработало.   -  person DLaw    schedule 26.05.2014


Ответы (2)


Вам просто нужно

def fooOnState[T](ft: Foo[T]) = ft.foo(ft.state)

называть это с помощью Foo[_] нормально.

Тем не менее, экзистенциалов в большинстве случаев лучше избегать, но это зависит от вашего реального кода.

person Didier Dupont    schedule 25.05.2014
comment
Это сработает, но как мне получить доступ к T, который мне нужен для вызова fooOnState? У меня есть много разных подклассов Foo, каждый со своим T и т. д. - person DLaw; 26.05.2014
comment
Не уверен, что понимаю, вы можете вызвать fooOnState, передав ему Foo[_], в вашем коде просто вызовите fooOnState(f), а не f.foo(f.state), для этого вам не требуется знать T. - person Didier Dupont; 26.05.2014
comment
Мои извинения, я не знал, что вы можете опустить этот параметр типа при вызове. Принятый! - person DLaw; 26.05.2014

Замена параметра типа на «член типа» в трейте позволит вам написать универсальный код, который работает для всех типов состояний, за счет небольшого количества подробностей для указания члена типа в каждом подклассе:

trait Foo {
  type StateT  // this is the "type member"
  val state: StateT
  def foo(arg: StateT): Unit
}

class Bar(myNumber: Int) extends Foo {
  type StateT = Int     // this is the verbose part
  override val state = myNumber  // this, too
  override def foo(arg: StateT) { /* something specific here */ }
}

class Baz(val f: Foo) {
  f.foo(f.state)  // generic code, works on any Foo subclass
}
person Ben Kovitz    schedule 25.05.2014