【问题标题】:AnyRef equivalent for an AnyVal typeAnyVal 类型的 AnyRef 等效项
【发布时间】:2018-05-14 04:34:18
【问题描述】:

给定一个类型T,是否有一种惯用的Scala 方式来描述AnyRef 等效于T(我们称之为ARE[T])。例如,

  • ARE[T <: AnyRef] 是 T
  • ARE[T <: AnyVal] 是 java.lang.* 相当于 T 存在时或编译错误时不存在

问题的目的是允许实现许多方法,例如:

def foo[A](...): ARE[A]

同时避免 Boolean、Byte、Char、Double、Float、Int、Long 和 Short 的幼稚 def foo[A <: AnyRef](...): A + 重载。

【问题讨论】:

  • 您希望通过限制AnyVal 获得什么?避免拳击?
  • @YuvalItzchakov 的目标不是避免装箱:根据定义,AnyRef-等效类型是堆分配的。目标是顺利使用需要T <: AnyRef的非标准集合。
  • 如果我理解正确,您是在问 Scala 语言是否公开了 ARE[A] 等效项以允许您使用它而不是在任何地方限制 T?

标签: scala types


【解决方案1】:

实现这种类型计算的标准方法是创建一个类型类:

sealed trait Box[T] {
  type Out
  def apply(t: T): Out
}

object Box {
  type Aux[T, ARE] = Box[T] { type Out = ARE }

  def make[T, ARE](f: T => ARE): Box.Aux[T, ARE] = new Box[T] {
    type Out = ARE
    def apply(t: T) = f(t)
  }

  implicit val int: Box.Aux[Int, java.lang.Integer] = make(Int.box)
  implicit val long: Box.Aux[Long, java.lang.Long] = make(Long.box)
  implicit val short: Box.Aux[Short, java.lang.Short] = make(Short.box)
  implicit val byte: Box.Aux[Byte, java.lang.Byte] = make(Byte.box)
  implicit val char: Box.Aux[Char, java.lang.Character] = make(Char.box)
  implicit val float: Box.Aux[Float, java.lang.Float] = make(Float.box)
  implicit val double: Box.Aux[Double, java.lang.Double] = make(Double.box)
  implicit val boolean: Box.Aux[Boolean, java.lang.Boolean] = make(Boolean.box)
  implicit val unit: Box.Aux[Unit, scala.runtime.BoxedUnit] = make(Unit.box)
  implicit def anyRef[T <: AnyRef]: Box.Aux[T, T] = make(identity)

  def box[T](t: T)(implicit are: Box[T]): are.Out = are(t)
}

这可以像任何其他类型类一样使用。例如,您可以在自己的函数中借助Box.Aux 计算类型ARE:

def box2[T, ARE](t: T)(implicit box: Box.Aux[T, ARE]): ARE = box(t)

当需要AnyRef 时,Scala 接受Box.box 的输出:

scala> def foo[T <: AnyRef](anyRef: T): T = anyRef
foo: [T <: AnyRef](anyRef: T)T

scala> foo(10)
<console>:13: error: inferred type arguments [Int] do not conform to method foo's type parameter bounds [T <: AnyRef]
       foo(10)
       ^
<console>:13: error: type mismatch;
 found   : Int(10)
 required: T
       foo(10)
           ^

scala> foo(Box.box(10))
res1: Box.int.Out = 10

Scala 还知道从Box.box 返回的确切ARE 类型:

scala> def bar[T](t: T)(implicit ev: T =:= java.lang.Integer) = ev
bar: [T](t: T)(implicit ev: =:=[T,Integer])=:=[T,Integer]

scala> bar(10)
<console>:13: error: Cannot prove that Int =:= Integer.
       bar(10)
          ^

scala> bar(Box.box(10))
res2: =:=[Box.int.Out,Integer] = <function1>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-13
    • 2017-01-01
    • 2017-05-02
    • 1970-01-01
    • 2010-11-13
    • 2010-09-24
    • 2019-03-26
    相关资源
    最近更新 更多