简体   繁体   English

从实例化的类(Scala)中访问值的父命名?

[英]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! 谢谢你的帮助!

Edit 编辑

This question may be helpful: How can I get the memory location of a object in java? 这个问题可能会有所帮助: 如何获取Java中对象的内存位置?

Edit 2 编辑2

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.

相关问题 如何访问从Java中抽象类的子类实例化的对象? - How do I access the object that's been instantiated from the abstract class's subclass in java? 如何从另一个类更新在RecyclerView的ViewHolder中实例化的进度条? - How to update a progressbar that is instantiated within a RecyclerView's ViewHolder, from a different class? 使用可选参数从Java访问Scala的case类 - Access scala's case class from java with optional parameters 从静态上下文中获取测试类名称 - Get test class name within static context from it's parent 从C#中的子类访问父方法 - Access Parent's method from child class in C# 如何从子类中访问父类中的内部类? - How can I access a inner class in a Parent class from within a Child class? 已实例化但未存储的实体的访问密钥[objectify] [@prepersist] - Access Key from Entity that's instantiated but not stored [objectify] [@prepersist] 从父类中调用父方法 - Calling parent method from within the parent class 为什么允许使用子类的构造函数实例化父类对象? - Why is it allowed for a parent class object to be instantiated using a child class's constructor? 可以在静态方法中实例化的匿名内部类是否可以访问包含类的实例成员? - Can Anonymous inner class instantiated within a static method has access to instance members of containing class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM