【问题标题】:Establishing a known 1:1 relationship between a type and a unique value在类型和唯一值之间建立已知的 1:1 关系
【发布时间】:2011-07-06 05:17:13
【问题描述】:

鉴于我有一种使用密封特征和表示值的案例对象的枚举,是否可以强制执行一种机制来检索给定类型的单个唯一值,而不需要隐式参数?

隐含这将是

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 = ???
}

?

【问题讨论】:

  • 我不知道你想用这个诡计来达到什么目的。为什么不能只使用 Java 类型安全枚举?
  • @yhwong:我希望能够创建一个方法,例如 def fill[R &lt;: Rate](n: Int)(fun: =&gt; GE[R]) : Mix[R] where trait GE[R &lt;: Rate] { def rate: R }trait Mix[R &lt;: Rate] extends GE[R] 这样我就可以用n == 0 调用fill 并且仍然可以能够构造Mix,尽管无法从对fun 的任何调用中检索R 的值。当涉及另一个间接时,添加 R 的隐式值会导致类型推断出现一些问题,例如def disjoint[R &lt;: Rate, G &lt;: GE[R]](n: Int)(fun: =&gt; G): G
  • @yhwong:另一种解释“为什么”:理想情况下,我不需要GER 提供值,这可以留给GE 的具体实例。但是,我需要能够在 GE 上调用二元运算符,它构造一个目标 GE,其类型参数 R 取决于操作数的类型参数,例如 (a: GE[audio]) * (b: GE[control]) 产生 HigherRate[audio, control]。虽然这一切都可以在不传递 R 的值的情况下完成,但我希望能够允许轻松的动态输入,这样我就可以做到 someGE.rate match { ... }

标签: scala types enumeration implicit-conversion sealed


【解决方案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

这完全一样,手动删除编译器会为你做的上下文边界的语法糖。

基本上,这一切都有效,因为编译在解析隐式时也会考虑类型参数。

如果您想了解更多关于这类事情的信息,搜索的神奇短语是“类型类”

【讨论】:

  • 谢谢,凯文。你能告诉我为什么上面的更好,即为什么要求间接隐式将 Enum 作为类型参数而不是要求 Enum 的隐式值?在测试的方法签名方面,我仍然看到需要一个隐式证据参数,所以我想知道你的方法有什么优势?
  • 轻率的回答是“我的方法更好,因为它确实有效”。使用您的方法,您将一个类型传递给一个函数,然后期望该函数以某种方式定位该类型的单例。这在逻辑上等同于在板条箱上贴上一个标签,说明“用你会在里面找到的撬棍打开”,我只是把撬棍放在外面......你会发现这种模式在 Scala 中被广泛使用,Numeric就是一个很好的例子。
  • 另一个优点是您可以使用它从任何其他类型中查找任何类型,它不仅限于伴随类/对象对 - 这实际上是类型类的一种非常不寻常的安排.
猜你喜欢
  • 2019-12-16
  • 1970-01-01
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 2014-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多