值类引入了不需要的公共方法

0__*_*0__ 15 visibility scala named-parameters value-class

看一下我的库的一些scala-docs,在我看来,值类中有一些不需要的噪音.例如:

implicit class RichInt(val i: Int) extends AnyVal {
  def squared = i * i
}
Run Code Online (Sandbox Code Playgroud)

这引入了不必要的符号i:

4.i   // arghh....
Run Code Online (Sandbox Code Playgroud)

那些东西出现在scala文档和IDE自动完成中,这实际上并不好.

那么......关于如何缓解这个问题的任何想法?我的意思是你可以使用,RichInt(val self: Int)但这不会让它变得更好(4.self,是吗?)


编辑:

在以下示例中,编译器是否擦除了中间对象?

import language.implicitConversions

object Definition {
  trait IntOps extends Any { def squared: Int }
  implicit private class IntOpsImpl(val i: Int) extends AnyVal with IntOps {
    def squared = i * i
  }
  implicit def IntOps(i: Int): IntOps = new IntOpsImpl(i)  // optimised or not?
}

object Application {
  import Definition._
  // 4.i  -- forbidden
  4.squared
}
Run Code Online (Sandbox Code Playgroud)

Rex*_*err 5

它确实引入了噪声(注意:在2.10中,在2.11及更高版本中,您只需声明val私有).你并不总是想要.但这就是现在的方式.

您无法通过遵循私有值类模式来解决问题,因为编译器实际上无法在其末尾看到它是一个值类,因此它将通过通用路由.这是字节码:

   12: invokevirtual #24;
          //Method Definition$.IntOps:(I)LDefinition$IntOps;
   15: invokeinterface #30,  1;
          //InterfaceMethod Definition$IntOps.squared:()I
Run Code Online (Sandbox Code Playgroud)

看看第一个如何返回该类的副本Definition$IntOps?它是盒装的.

但这两种模式有用,有点像:

(1)通用名称模式.

implicit class RichInt(val repr: Int) extends AnyVal { ... }
implicit class RichInt(val underlying: Int) extends AnyVal { ... }
Run Code Online (Sandbox Code Playgroud)

使用其中之一.添加i作为一种方法很烦人.underlying当没有任何潜在的东西时添加并不是那么糟糕 - 如果你试图获得潜在价值,你只会点击它.如果你一遍又一遍地使用相同的名称:

implicit class RicherInt(val repr: Int) extends AnyVal { def sq = repr * repr }
implicit class RichestInt(val repr: Int) extends AnyVal { def cu = repr * repr * repr }

scala> scala> 3.cu
res5: Int = 27

scala> 3.repr
<console>:10: error: type mismatch;
 found   : Int(3)
 required: ?{def repr: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method RicherInt of type (repr: Int)RicherInt
 and method RichestInt of type (repr: Int)RichestInt
Run Code Online (Sandbox Code Playgroud)

名称碰撞sorta无论如何都要处理你的问题.如果您真的想要,可以创建一个仅存在与之冲突的空值类repr.

(2)显式隐式模式

有时候,你想在内部你的价值被命名为比其他更短或更多记忆reprunderlying没有使它可在原来的类型.一种选择是创建隐式转发,如下所示:

class IntWithPowers(val i: Int) extends AnyVal {
  def sq = i*i
  def cu = i*i*i 
}
implicit class EnableIntPowers(val repr: Int) extends AnyVal { 
  def pow = new IntWithPowers(repr)
}
Run Code Online (Sandbox Code Playgroud)

现在你必须调用3.pow.sq而不是 - 这3.sq可能是一个很好的方法来分割你的命名空间! - 你不必担心超出原始的命名空间污染repr.


Ric*_*ich 5

在Scala 2.11中,您可以将val设为私有,这可以解决此问题:

implicit class RichInt(private val i: Int) extends AnyVal {
  def squared = i * i
}
Run Code Online (Sandbox Code Playgroud)