Установление известного отношения 1:1 между типом и уникальным значением
Учитывая, что у меня есть своего рода перечисление, использующее запечатанные признаки и объекты case, представляющие значения, возможно ли применить механизм для извлечения единственного уникального значения для данного типа, не требуя неявного аргумента?
с последствиями это будет
sealed trait Enum
sealed trait Value1 extends Enum
case object Value1 extends Value1 { implicit val me: Value1 = Value1 }
sealed trait Value2 extends Enum
case object Value2 extends Value2 { implicit val me: Value1 = Value1 }
def test[V <: Enum](implicit evidence: V): V = evidence
test[Value1]
Можно ли отбросить неявный аргумент для проверки? то есть, чтобы убедиться, что V является определенным подтипом Enum (очевидно, test[Enum] должен провалиться). Гордиев узел:
object Enum {
def unique[V <: Enum]: V = ???
}
?
1 ответ
Похоже, что вы пытаетесь найти конкретные значения или поведение в зависимости от типа и по какой-либо причине не хотите помещать это поведение в какой-то общий суперкласс.
Выглядит так, как будто вы пытаетесь использовать импликации и сопутствующие объекты для достижения этой цели, эмулируя некоторые характеристики статики Java. Это модель, которую вы абсолютно хотите исключить из своего ментального инструментария, она безнадежно сломана с точки зрения объектно-ориентированного программирования.
То, что вы действительно хотите, это специальный полиморфизм, и у нас есть лучшие способы сделать это. Интересно, что он все еще использует импликации и привязку к контексту:
sealed trait Enum
sealed trait Value1 extends Enum
sealed trait Value2 extends Enum
case object Value1 extends Value1
case object Value2 extends Value2
sealed abstract class UniqValue[T] { def value: T }
implicit object Value1HasUniq extends UniqValue[Value1] { val value = Value1 }
implicit object Value2HasUniq extends UniqValue[Value2] { val value = Value2 }
def test[V <: Enum : UniqValue]: V = implicitly[UniqValue[V]].value
Вы также можете определить test
как:
def test[V <: Enum](implicit ev: UniqValue[V]): V = ev.value
Что делает то же самое, вручную удаляя синтаксический сахар границ контекста, который компилятор сделает для вас в любом случае.
По сути, все это работает, потому что компиляция также учитывает параметры типа при разрешении имплицитов.
Если вы хотите больше узнать об этом, волшебная фраза для поиска - "классы типов"