【问题标题】:Access a value's parent naming from within the instantiated class (Scala)?从实例化类(Scala)中访问值的父命名?
【发布时间】:2017-03-21 13:27:15
【问题描述】:

假设 Scala 2.11。我正在编写一个将保留 Scala 值的类。它的意图是这样使用:

class ParentClass {

  val instanceId: String = "aUniqueId"

  val statefulString: Persisted[String] = persisted { "SomeState" }

  onEvent {
    case NewState(state) => statefulString.update(state)
  }

}

Persisted 是一个具有类型参数的类,用于像缓存一样持久化特定值,Persist 处理与持久性相关的所有逻辑。但是,为了简单地实现,我希望检索有关它的实例化的信息。例如,如果它在父类中的实例名为statefulString,我如何从Persisted 类本身中访问该名称?

这样做的目的是在简化 API 的同时防止持久值的自动命名发生冲突。我不能依赖使用类型,因为String 类型可能有多个值。

感谢您的帮助!

编辑

这个问题可能会有所帮助:How can I get the memory location of a object in java?

编辑 2

阅读ScalaCache 的源代码后,似乎可以通过WeakTypeTag 执行此操作。有人能解释一下它的宏到底发生了什么吗?

https://github.com/cb372/scalacache/blob/960e6f7aef52239b85fa0a1815a855ab46356ad1/core/src/main/scala/scalacache/memoization/Macros.scala

【问题讨论】:

    标签: java scala reflection introspection


    【解决方案1】:

    在 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"))
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-21
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 2011-02-21
      相关资源
      最近更新 更多