添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在 Scala 中实现引用

C++ 里引用是一个非常有用的工具。虽然 Scala 没有提供引用作为原生语法,但是我们能够轻松的使用不到 100 行代码来模拟出 C++ 的引用:


trait Ref[+A] {
  def get: A
  override def toString: String = s"Ref($get)"
trait MutableRef[A] {
  def get: A
  def set(value: A): Unit
  def update(value: A): Unit = set(value)
  override def toString: String = s"MutableRef($get)"
import scala.language.experimental.macros
import scala.language.implicitConversions
import scala.reflect.macros.blackbox
implicit def &[A](value: => A): Ref[A] = new Ref[A] {
  override def get: A = value
implicit def &&[A](value: => A): MutableRef[A] = macro refMacro[A]
implicit def *[A](ref: Ref[A]): A = ref.get
implicit def *[A](ref: MutableRef[A]): A = ref.get
def refMacro[A: c.WeakTypeTag](c: blackbox.Context)(value: c.Tree): c.Tree = {
  import c.universe._
  val tpe = weakTypeOf[A]
  q"""
      new MutableRef[$tpe] {
        def get: $tpe = $value
        def set(value: $tpe): Unit = $value = value
implicit def mutableRef2ref[A](mutableRef: MutableRef[A]): Ref[A] = &(mutableRef.get)

然后我们可以做几个实验:

//immutable reference
var a: Int = 10
val aRef: Ref[Int] = a
assert(aRef.get == 10)
a = 100
assert(aRef.get == 100)
//mutable reference
var b: Int = 10
val bRef: MutableRef[Int] = b
assert(bRef.get == 10)
b = 100
assert(bRef.get == 100)
bRef.set(50)
assert(b == 50)
//swap
def swap[A](a1: MutableRef[A], a2: MutableRef[A]): Unit = {
  val n = a1.get
  a1.set(a2.get)
  a2.set(n)
var a1 = 10