Scala: как добавить зависящие от типа методы в признаке?

У меня есть следующая идея:

trait Generator[A] {
 def generate: Stream[A]
 // (1) If A <: Int
 def +(other: Generator[Int]): Generator[Int] = (
 CustomGeneratorInt(
 (this.asInstanceOf[Generator[Int]].generate, other.generate)
 .zipped
 .map(_ + _))
 )
 // (2) If A <: Boolean
 def &&(other: Generator[Boolean]): Generator[Boolean] = ...
}
case class CustomGeneratorInt(val generate: Stream[Int]) extends Generator[Int]
case class ConstantInt(i: Int) extends Generator[Int] { def generate = Stream(i) }
case class ConstantBool(i: Boolean) extends Generator[Boolean] { def generate = Stream(i) }
case class GeneratorRandomInt(i: Int) extends Generator[Int] { def generate = ... }
ConstantInt(1) + ConstantInt(2) // (3) ok
ConstantBool(true) && ConstantBool(false) // (4) ok
ConstantInt(1) + ConstantBool(false) // (5)
ConstantBool(true) + ConstantInt(1) // (6) compiles but it bad
ConstantBool(true) && ConstantInt(1) // (7)
ConstantInt(1) && ConstantBool(true) // (8) compiles but it bad

Я хотел бы (1) и (2) поднять исключение компилятора, если они не применяются в правильной схеме. Например, хотя (6) и (8) в настоящее время компилируются, они не должны. (5) и (7) уже не компилируются. Как указать это условие типа для применения этих методов?

1 ответ

Вы можете использовать ограничения обобщенного типа (см. этот ответ) для достижения того, что вы хотите:

trait Generator[A] {
 def generate: Stream[A]
 def +(other: Generator[A])(implicit evidence: A =:= Int): Generator[Int] = ???
 def &&(other: Generator[A])(implicit evidence: A =:= Boolean): Generator[Boolean] = ???
}
case class GeneratorInt(i: Int) extends Generator[Int] { def generate = Stream(i) }
case class GeneratorBool(i: Boolean) extends Generator[Boolean] { def generate = Stream(i) }
GeneratorInt(1) + GeneratorInt(2) // (3) ok
GeneratorBool(true) && GeneratorBool(false) // (4) ok
GeneratorInt(1) + GeneratorBool(false) // (5) type mismatch
GeneratorBool(true) + GeneratorInt(1) // (6) type mismatch
GeneratorBool(true) && GeneratorInt(1) // (7) type mismatch
GeneratorInt(1) && GeneratorBool(true) // (8) type mismatch

licensed under cc by-sa 3.0 with attribution.