通过Scala中的含义"装箱"原始类型的开销

zig*_*tar 6 scala implicit-conversion

假设我想要一个像Java这样的类Date.它唯一的数据成员是一个long,表示自1970年以来的毫秒数.

是/可能只是制作新的Scala类型的任何性能优势:

type PrimitiveDate = Long
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用隐式转换添加方法,就像对int一样RichInt.原始类型的这种"拳击"是否涉及任何开销(类创建)?基本上你可以有一个静态方法

def addMonth(date: PrimitiveDate, months: Int): PrimitiveDate = date + 2592000000 * months
Run Code Online (Sandbox Code Playgroud)

让类型系统弄清楚它必须d addMonth 5 在代码中出现时应用.

编辑

看来你通过编写创建的别名type PrimitiveDate = Long不是由scala编译器强制执行的.创建一个合适的类,包含Long,这是在Scala中创建强制类型的唯一方法吗?

您认为能够为基本类型创建强制类型别名有用吗?

oxb*_*kes 11

好吧,转义分析应该意味着最新的JVM实际上不必创建丰富的包装器来调用该addMonth方法.

实际上在实践中实际发生的程度显然取决于JVM决定这些方法在对象创建中添加多少运行时热点.当没有进行转义分析时,显然JVM必须Long在包装类的新实例中"装箱"(如你所说).它不涉及"类创建" - 它将涉及"创建类的实例".这个短暂的实例将立即成为GC-d,因此开销(虽然很小)是:

  • 实例的内存分配
  • GC实例化

如果您正在编写非常低延迟的代码,而您正在尝试最小化垃圾创建(在紧密的循环中),这些显然只会出现任何问题.只有你知道是否是这种情况.

至于这种方法是否适合你(逃避分析来帮助你),你必须在野外进行测试.众所周知,微基准测试很难用于此类事情.


我不太喜欢将这些类型别名作为公共API的一部分的原因是scala并没有像我希望的那样严格执行它们.例如:

type PrimitiveDate = Long
type PrimitiveSpeed = Long
type Car = String
type Meeting = String

var maxSpeeds : Map[Car, PrimitiveSpeed] = Map.empty

//OOPS - much too easy to accidentally send the wrong type
def setDate(meeting : Meeting, date : PrimitiveDate) = maxSpeeds += (meeting -> date)
Run Code Online (Sandbox Code Playgroud)