Как иметь один ковариантный параметр в классе, а также функцию для его преобразования? - PullRequest
0 голосов
/ 02 мая 2020

У меня очень простой класс:

case class Foo[+T](t: T)

Теперь я хочу добавить аргумент для преобразования T в Int. По определенным c причинам я не хочу использовать класс типов, неявное или какое-либо наследуемое решение, потому что это действительно то, что я моделирую: класс, содержащий некоторые данные и функцию для их преобразования.

Поэтому я пишу

case class Foo[+T](t: T, f: T => Int)

или

case class Foo[+T](t: T, f: Function1[T, Int])

Конечно, это не сработает, потому что f контравариантно по T. Любое решение?

1 Ответ

2 голосов
/ 02 мая 2020

Вы можете попробовать экзистенциальный тип

case class Foo[+T](t: T, f: (_ <: T) => Int)

, но на самом деле (_ <: T) => Int это просто Nothing => Int.

(в Dotty также возможно иметь case class Foo[+T](t: T, f: [U <: T] => U => Int).)

Рассмотрите возможность добавления еще одного параметра типа

case class Foo[+T, U <: T](t: T, f: U => Int)

Тогда вы можете использовать "частично примененный" шаблон, когда хотите, чтобы U был выведен

def mkFoo[T] = new PartiallyApplied[T]
class PartiallyApplied[T] {
  def apply[U <: T](t: T, f: U => Int) = Foo(t, f)
}

trait Parent
case class Child(i: Int) extends Parent

mkFoo[Parent](new Parent {}, (c: Child) => c.i)

Еще одна опция - это сделать U членом типа

trait Foo[+T] {
  type U <: T
  val t: T
  val f: U => Int
}

object Foo {
  def apply[T, _U <: T](_t: T, _f: _U => Int): Foo[T] { type U = _U } = new Foo[T] {
    override type U = _U
    override val t: T = _t
    override val f: U => Int = _f
  }

  def unapply[T](foo: Foo[T]): Option[(T, foo.U => Int)] = Some((foo.t, foo.f))
}

Возможно, ваш класс может быть

case class Foo[+T](t: T) { 
  def f[U >: T](t1: U): Int = ??? 
}

В противном случае это просто инвариант case class Foo[T](t: T, f: T => Int).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...