[英]Access a value's parent naming from within the instantiated class (Scala)?
Assume Scala 2.11. 假设Scala 2.11。 I'm writing a class that will persist a Scala value. 我正在写一个将保留Scala值的类。 It's intention is to be used as such: 目的是这样使用:
class ParentClass {
val instanceId: String = "aUniqueId"
val statefulString: Persisted[String] = persisted { "SomeState" }
onEvent {
case NewState(state) => statefulString.update(state)
}
}
Persisted
is a class with a type parameter that is meant to persist that specific value like a cache, and Persist
handles all of the logic associated with persistence. Persisted
是一个带有类型参数的类,该类型参数用于像缓存一样保留该特定值,而Persist
处理与持久性相关的所有逻辑。 However, to simply the implementation, I'm hoping to retrieve information about it's instantiation. 但是,为了简化实现,我希望检索有关其实例化的信息。 For example, if it's instance in the parent class is named statefulString
, how can I access that name from within the Persisted
class itself? 例如,如果它在父类中的实例名为statefulString
,我如何从Persisted
类本身内部访问该名称?
The purpose of doing this is to prevent collisions in automatic naming of persisted values while simplifying the API. 这样做的目的是在简化API的同时防止自动命名持久值时发生冲突。 I cannot rely on using type, because there could be multiple values of String
type. 我不能依靠使用类型,因为可能有多个String
类型的值。
Thanks for your help! 谢谢你的帮助!
This question may be helpful: How can I get the memory location of a object in java? 这个问题可能会有所帮助: 如何获取Java中对象的内存位置?
After reading the source code for ScalaCache
, it appears there is a way to do this via WeakTypeTag
. 阅读完ScalaCache
的源代码ScalaCache
,似乎可以通过WeakTypeTag
进行此WeakTypeTag
。 Can someone explain what exactly is happening in its macros? 有人可以解释其宏中到底发生了什么吗?
https://github.com/cb372/scalacache/blob/960e6f7aef52239b85fa0a1815a855ab46356ad1/core/src/main/scala/scalacache/memoization/Macros.scala https://github.com/cb372/scalacache/blob/960e6f7aef52239b85fa0a1815a855ab46356ad1/core/src/main/scala/scalacache/memoization/Macros.scala
I was able to do this with the help of Scala macros and reflection, and adapting some code from ScalaCache: 我能够在Scala宏和反射的帮助下,并从ScalaCache修改一些代码来做到这一点:
class Macros(val c: blackbox.Context) {
import c.universe._
def persistImpl[A: c.WeakTypeTag, Repr: c.WeakTypeTag](f: c.Tree)(keyPrefix: c.Expr[ActorIdentifier], scalaCache: c.Expr[ScalaCache[Repr]], flags: c.Expr[Flags], ec: c.Expr[ExecutionContext], codec: c.Expr[Codec[A, Repr]]) = {
commonMacroImpl(keyPrefix, scalaCache, { keyName =>
q"""_root_.persistence.sync.caching($keyName)($f)($scalaCache, $flags, $ec, $codec)"""
})
}
private def commonMacroImpl[A: c.WeakTypeTag, Repr: c.WeakTypeTag](keyPrefix: c.Expr[ActorIdentifier], scalaCache: c.Expr[ScalaCache[Repr]], keyNameToCachingCall: (c.TermName) => c.Tree): Tree = {
val enclosingMethodSymbol = getMethodSymbol()
val valNameTree = getValName(enclosingMethodSymbol)
val keyName = createKeyName()
val scalacacheCall = keyNameToCachingCall(keyName)
val tree = q"""
val $keyName = _root_.persistence.KeyStringConverter.createKeyString($keyPrefix, $valNameTree)
$scalacacheCall
"""
tree
}
/**
* Get the symbol of the method that encloses the macro,
* or abort the compilation if we can't find one.
*/
private def getValSymbol(): c.Symbol = {
def getValSymbolRecursively(sym: Symbol): Symbol = {
if (sym == null || sym == NoSymbol || sym.owner == sym)
c.abort(
c.enclosingPosition,
"This persistence block does not appear to be inside a val. " +
"Memoize blocks must be placed inside vals, so that a cache key can be generated."
)
else if (sym.isTerm)
try {
val termSym = sym.asInstanceOf[TermSymbol]
if(termSym.isVal) termSym
else getValSymbolRecursively(sym.owner)
} catch {
case NonFatal(e) => getValSymbolRecursively(sym.owner)
}
else
getValSymbolRecursively(sym.owner)
}
getValSymbolRecursively(c.internal.enclosingOwner)
}
/**
* Convert the given method symbol to a tree representing the method name.
*/
private def getValName(methodSymbol: c.Symbol): c.Tree = {
val methodName = methodSymbol.asMethod.name.toString
// return a Tree
q"$methodName"
}
private def createKeyName(): TermName = {
// We must create a fresh name for any vals that we define, to ensure we don't clash with any user-defined terms.
// See https://github.com/cb372/scalacache/issues/13
// (Note that c.freshName("key") does not work as expected.
// It causes quasiquotes to generate crazy code, resulting in a MatchError.)
c.freshName(c.universe.TermName("key"))
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.