代码之家  ›  专栏  ›  技术社区  ›  ziggystar

我可以使用Scala的Dynamic以编程方式创建某个特性的对象实例吗?

  •  0
  • ziggystar  · 技术社区  · 6 年前

    trait T 给定为对象,类似于以下内容,忽略arity:

    case class Method[T,A,B](name: String, f: T => A => B)
    

    所以考虑到一些特点 T ,这可能看起来像:

    trait T{
      def foo(i: Int): String
      def bar(s: String): Unit
    }
    
    def methodsOfT: Seq[Method[T,_,_]] = Seq(
      Method("foo", t => i => t.foo(i)),
      Method("bar", t => s => t.bar(s))
    )
    

    T型 T型 ,不管怎样,它使用了 Method 要实现的对象 T型

    它可能如下所示(这不会编译):

    def reify[T](impl: T, methods: Method[T,_,_]): T = (new Object with Dynamic {
      def applyDynamic(method: String)(args: Any*): Any = {
        //do something here
      }
    }).asInstanceOf[T]  //<- will fail at runtime
    

    Object ,并且不能强制转换为类型/类 T型 . 有办法解决这个问题吗?

    为什么我要这么做

    我有一个特点 T型 我想为它创建一个远程调用接口。在客户端,我需要一个 T型 RemoteT . 但代码完全是样板文件。

    new T {
      def foo(i: Int): String = 
        methodsOfT.find(_.name == "foo").get.f(i).asInstanceOf[String]
      def bar(s: String): Unit = 
        methodsOfT.find(_.name == "bar").get.f(s).asInstanceOf[Unit]
    }
    

    我想我可以使用宏来合成方法重写并将它们转发给网络远程处理程序。但我还是尽量避免宏。

    附笔。

    Java Reflection: Create an implementing class

    1 回复  |  直到 6 年前
        1
  •  2
  •   Mateusz Kubuszok    6 年前

    我相信类似的事情是在不成形的情况下完成的。

    Here 可以看到,dynamics将镜头的创建委托给隐式返回类型 functional depenencies (这里:那个 mkLens.Out

    trait Lens[S, A] extends LPLens[S, A] { outer =>
    ...
      def selectDynamic(k: String)
        (implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, Symbol @@ k.type, Nothing]): mkLens.Out = mkLens(this)
    ...
    }
    

    透镜本身不是用宏产生的,而是用正常的推导,但是 you can use macro 要生成隐式,应该是可能的。

    object Generic1 extends Generic10 {
    ...
    
      implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] =
        macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[t, U] })#λ]
    
    ...
    }
    

    宏+动态的组合用于 HList .

    object HList extends Dynamic {
    ...
      /**
       * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows,
       *
       * {{{
       * type ISB = HList.`Int, String, Boolean`.T
       * }}}
       *
       * Literal types are allowed, so that the following is valid,
       *
       * {{{
       * type ABC = HList.`'a, 'b, 'c`.T
       * type TwoTrueStr = HList.`2, true, "str"`.T
       * }}}
       */
      def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.hlistTypeImpl
    ...
    }
    

    总之,你应该能够实现你的目标。这一切都取决于你到底想如何实例化你的对象-例如,take implicit ClassTag HList 使用 Generic 把它变成一个特定的表示或者其他的东西。