あなたはおそらく同様にこのアイデアを考えたが、何このようなものについて:
class StringOrIntOrDouble private(val first: Option[String], val second: Option[Int], val third: Option[Double]) {
def this(first: String) = this(Some(first), None, None)
def this(second: Int) = this(None, Some(second), None)
def this(third: Double) = this(None, None, Some(third))
def this(first: String, second: Int) = this(Some(first), Some(second), None)
def this(second: Int, third: Double) = this(None, Some(second), Some(third))
def this(first: String, third: Double) = this(Some(first), None, Some(third))
def this(first: String, second: Int, third: Double) = this(Some(first), Some(second), Some(third))
}
主なコンストラクタは、そうあなたが空のインスタンスを作成することはできませんprivate
です。明らかに、Product
とequals
、hashCode
、toString
のような実装と、ケースクラスのような他の有用な事柄を拡張することができます(ただし、不変式を簡単に破る可能性があるのでcopy
に注意してください)。
残念ながら、汎用バージョン(または2つの場所で同じタイプ)を使用する場合は、名前付きメソッドのすべての「サブセット」コンストラクタをコンパニオンオブジェクトに移動する必要があります。そうしないと、タイプ消去のためにコンパイルされません。
class TripleIor[+A, +B, +C] private(val first: Option[A], val second: Option[B], val third: Option[C]) {
}
object TripleIor {
def first[A](first: A) = new TripleIor[A, Nothing, Nothing](Some(first), None, None)
def second[B](second: B) = new TripleIor[Nothing, B, Nothing](None, Some(second), None)
def third[C](third: C) = new TripleIor[Nothing, Nothing, C](None, None, Some(third))
def firstAndSecond[A, B](first: A, second: B) = new TripleIor[A, B, Nothing](Some(first), Some(second), None)
def secondAndThird[B, C](second: B, third: C) = new TripleIor[Nothing, B, C](None, Some(second), Some(third))
def firstAndThird[A, C](first: A, third: C) = new TripleIor[A, Nothing, C](Some(first), None, Some(third))
def apply[A, B, C](first: A, second: B, third: C) = new TripleIor[A, B, C](Some(first), Some(second), Some(third))
}
より根本的な方法は、sealed trait
と7サブクラスと同じアイデアを実装することですが、私は彼らが使用する方がはるかに簡単だろうとは思いません。また、copy
をタイプセーフな方法で実装することができますが、多くのタイプの入力コストがかかります(ここには示されていません)。
sealed trait TripleIor[A, B, C] extends Product {
def firstOption: Option[A]
def secondOption: Option[B]
def thirdOption: Option[C]
}
object TripleIor {
final case class First[A](first: A) extends TripleIor[A, Nothing, Nothing] {
override def firstOption: Option[A] = Some(first)
override def secondOption: Option[Nothing] = None
override def thirdOption: Option[Nothing] = None
}
final case class Second[B](second: B) extends TripleIor[Nothing, B, Nothing] {
override def firstOption: Option[Nothing] = None
override def secondOption: Option[B] = Some(second)
override def thirdOption: Option[Nothing] = None
}
final case class Third[C](third: C) extends TripleIor[Nothing, Nothing, C] {
override def firstOption: Option[Nothing] = None
override def secondOption: Option[Nothing] = None
override def thirdOption: Option[C] = Some(third)
}
final case class FirstSecond[A, B](first: A, second: B) extends TripleIor[A, B, Nothing] {
override def firstOption: Option[A] = Some(first)
override def secondOption: Option[B] = Some(second)
override def thirdOption: Option[Nothing] = None
}
final case class SecondThird[B, C](second: B, third: C) extends TripleIor[Nothing, B, C] {
override def firstOption: Option[Nothing] = None
override def secondOption: Option[B] = Some(second)
override def thirdOption: Option[C] = Some(third)
}
final case class FirstThird[A, C](first: A, third: C) extends TripleIor[A, Nothing, C] {
override def firstOption: Option[A] = Some(first)
override def secondOption: Option[Nothing] = None
override def thirdOption: Option[C] = Some(third)
}
final case class All[A, B, C](first: A, second: B, third: C) extends TripleIor[A, B, C] {
override def firstOption: Option[A] = Some(first)
override def secondOption: Option[B] = Some(second)
override def thirdOption: Option[C] = Some(third)
}
}
P.S.ここにあるすべての例は、多くの有用で必要なものを実装していないアイデアを説明するためのスケッチです。
3つのオプションの値を持つクラスを使用することは大丈夫だと思います。条件を検証するインスタンスを作成するためのメソッドで、 'Option [YourClass]'、 '[Error、YourClass]'またはコードベースで使用しているものを返すことができます。 – AlexITC
あなたは正しいと思います。私は、それが型だけを使ってこれをエンコードするより自然な方法があるかどうかを知りたいのはまだ興味があります。 – yhm
私は 'cats.Ior'を使うか、あなたの7クラス' trait'をローリングするかは、理論的には健全なアプローチだと思います。 'cats.Ior'のデストラクタは3ウェイ'フォールド 'で、3ウェイタイプの7ウェイ 'フォールド'になります。これは扱いにくいです。あなたはこれらの価値観で何をするつもりですか? 3つのフィールドの間に何らかの自然優先がありますか?この質問に答えることで、「適切な」エンコーディングを簡単に決定することができます。 – ziggystar