在Scala中将动态对象与结构类型混合

时间:2013-04-03 21:41:17

标签: scala

有可能这样做吗? (我正在使用scala 2.10)调用一个方法,该方法要求对象具有名为“fullName”的函数,但是使用Dynamic trait构建的对象。编译器抱怨,但也许我做错了。

我不需要这个任何工作,我只是在学习语言。

import scala.language.dynamics

object Main extends App {

    class MyStatic {

        private var privateName = ""
        var lastName = ""

        def name_= (n: String) {
            privateName = n
        }

        def name = s"***$privateName***"

        def fullName = s"$name $lastName"

    }

    class MyDynamic extends scala.Dynamic {

        val map = collection.mutable.Map[String, String]()

        def selectDynamic(key: String): String = map(key)

        def updateDynamic(key: String)(value: String) {
            map += key -> value
        }

        def applyDynamic(key: String)(value: Any*) = key match {
            case "fullName" => {
                val name = map("name")
                val lastName = map("lastName")
                s"$name $lastName"
            }
        }

    }

    def showFullName(o: { def fullName: String }) = s"My full name is $o.fullName"

    println("Starting App...")

    val s = new MyStatic
    s.name = "Peter"
    s.lastName = "Parker"
    println(showFullName(s))

    val d = new MyDynamic
    d.name = "Bruce"
    d.lastName = "Wayne"
    println(showFullName(d))

}

2 个答案:

答案 0 :(得分:1)

结构类型{ def fullName: String }基本上意味着"任何名为fullName的无法方法返回String的类型。 MyDynamic没有这样的方法,因此不符合这种结构类型。 MyDynamic扩展scala.Dynamic的事实是无关紧要的:这意味着对于它的任何实例,您都可以像调用fullName一样执行看起来的内容,但它并不意味着MyDynamic(作为一种类型)有任何这样的成员。

所以简短的回答是没有,你不能将动态对象与结构类型混合起来。

为了完整性,我必须补充一点,可以按预期工作,但它需要编译器的特殊规定(即,编译器可以考虑比任何类型扩展{{ 1}} - 并实现所需的查找方法 - 与任何结构类型兼容,并且不像通常那样通过反射实现调用,而是通过调用相应的查找方法来实现。

答案 1 :(得分:0)

你正试图将两个完全不同的东西粘在一起。虽然结构类型有时也与'duck-typing'相比较,但它的功能正是使用静态类型信息(即使在使用站点上,字节代码也会调用反射)。根据定义,您的动态类型不具有此类静态类型信息。所以你永远无法说服Scala编译器你的动态类型有一个可以静态验证存在的方法。

唯一的解决方法是在showFullName中允许任何类型,并使用反射来调用fullName(同样,我不确定这是否与动态相关对象)。


另一方面,Scala会让您对动态类型做任何事情,将责任交给您:

def showFullName(o: Dynamic) = s"My full name is $o.fullName"

println(showFullName(d))