是否可以引用计数呼叫位置?

时间:2017-05-12 19:11:26

标签: scala

这个问题不是特定于编程语言的(越一般越好),但我在Scala中工作(不一定在JVM上)。是否有通过呼叫位置引用计数的方法,而不是总呼叫的数量?特别是,能够检测是否从多个呼叫位置调用给定方法将是很好的。

我想我可以通过对函数进行引用相等性检查来在某种程度上伪造它,但是这可以通过使用global-ish标记轻松滥用,甚至可以在同一范围内多次调用该函数:

sealed case class Token();
class MyClass[A] {
  var tokenOpt: Option[Token] = None
  def callMeFromOnePlace(x: A)(implicit tk: Token) = {
    tokenOpt match {
      case Some(priorTk) => if (priorTk ne tk) throw new IllegalStateException("")
      case None => tokenOpt = Some(tk)
    }
    // Do some work ...
  }
}

然后这应该可以正常工作:

val myObj = new MyClass[Int]
val myIntList = List(1,2,3)
implicit val token = Token()
myIntList.map(ii => myObj.callMeFromOnePlace(ii)) 

但不幸的是,这也是:

val myObj = new MyClass[Int]
implicit val token = Token()
myObj.callMeFromOnePlace(1)
myObj.callMeFromOnePlace(1) //oops, want this to fail

3 个答案:

答案 0 :(得分:1)

当您谈论呼叫位置时,它可以由调用堆栈跟踪表示。这是一个简单的例子:

// keep track of calls here (you can use immutable style if you want)
var callCounts = Map.empty[Int, Int]

def f(): Unit = {
  // calculate call stack trace hashCode for more efficient storage
  // .toSeq makes WrappedArray, that knows how to properly calculate .hashCode()
  val hashCode = new RuntimeException().getStackTrace.toSeq.hashCode()
  val callLocation = hashCode
  callCounts += (callLocation -> (callCounts.getOrElse(callLocation, 0) + 1))
}

List(1,2,3).foreach(_ =>
  f()
)
f()
f()
println(callCounts) // Map(75070239 -> 3, 900408638 -> 1, -1658734417 -> 1)

答案 1 :(得分:1)

我不完全清楚你想要做什么但是你的// oops ..例子失败你需要检查PriorTk不是None。 (请注意,它不是一个线程安全的解决方案)

答案 2 :(得分:1)

为了完整性,从类型系统角度强制执行这些约束需要线性类型。