阅读博客后,我得到的印象是,shapeless提供的标记类型没有运行时开销。
带有来自shapeless的标记类型的相关源代码:
object tag {
def apply[U] = new Tagger[U]
trait Tagged[U]
type @@[+T, U] = T with Tagged[U]
class Tagger[U] {
def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
}
}
对于带有示例代码的问题1:
trait IdTag
type Id = Long @@ IdTag
val id1: Id = tag[IdTag][Long](1000L) // way #1
val helper = tag[IdTag]
val id2: Id = helper[Long](1000L) // way #2
val id3: Id = 1000L.asInstanceOf[Id] // way #3
以#1和#2的方式tag[IdTag]
创建tag.Tagger[IdTag]
的实例,它是一个普通对象。 编译器是否会消除创建过程,以免产生运行时开销?还是创造成本如此之小,以至于人们只是忽略了它?
方法3是否合法,并且是避免中间对象创建的更好方法?
对于带有示例代码的问题2:
val m0: Map[Long, Double] = Map(...) // a very large map
val m1: Map[Id, Double] = m0.map(e => tag[IdTag][Long](e._1) -> e._2) // way #1
val helper = tag[IdTag]
val m2: Map[Id, Double] = m0.map(e => helper[Long](e._1) -> e._2) // way #2
val m3: Map[Id, Double] = m0.asInstanceOf[Map[Id, Double]] // way #3
从性能上来说,确实是#3方式是最好的,而#2方式则更糟,因为它需要遍历地图并创建新地图,而#3方式是最差的,因为它不需要仅遍历地图并创建新地图,还创建tag.Tagger
s的日志?