【问题标题】:Dynamic properties in ScalaScala 中的动态属性
【发布时间】:2011-07-18 23:42:28
【问题描述】:

Scala 是否支持动态属性之类的东西?示例:

val dog = new Dynamic // Dynamic does not define 'name' nor 'speak'.
dog.name = "Rex" // New property.
dog.speak = { "woof" } // New method.

val cat = new Dynamic
cat.name = "Fluffy"
cat.speak = { "meow" }

val rock = new Dynamic
rock.name = "Topaz"
// rock doesn't speak.

def test(val animal: Any) = {
   animal.name + " is telling " + animal.speak()
}

test(dog) // "Rex is telling woof"
test(cat) // "Fluffy is telling meow"
test(rock) // "Topaz is telling null"

在 Scala 中,我们能从中得到的最接近的东西是什么?如果有类似“addProperty”的东西允许像普通字段一样使用添加的属性,那就足够了。

我对结构类型声明(“类型安全的鸭子类型”)不感兴趣。我真正需要的是在运行时添加新的属性和方法,以便对象可以被期望添加的元素存在的方法/代码使用。

【问题讨论】:

  • 我认为“Topaz 告诉 null”很好地说明了为什么应尽可能避免此类事情。呃,我的意思是,汪汪。
  • 我同意。那只是一个例子。在现实世界中,我会使用它从 JSON 或 XML 读取域对象,如果属性不存在,我不希望它失败,也不想编写一些 if 或条件代码。下次我会尝试一个更好的例子。

标签: reflection scala dynamic


【解决方案1】:

Scala 2.9 将有一个经过特殊处理的 Dynamic trait,这可能是您正在寻找的。​​p>

这个博客有一个很大的:http://squirrelsewer.blogspot.com/2011/02/scalas-upcoming-dynamic-capabilities.html

我猜想在 invokeDynamic 方法中您需要检查“name_="、"speak_="、"name" 和 "speak",并且可以将值存储在私有映射中。

【讨论】:

  • Scala 2.9 的动态支持还很不完善。它不适用于 assignments 或 apply(),请参阅此处 link
【解决方案2】:

我想不出理由真的需要在运行时动态添加/创建方法/属性除非动态标识符也被允许-和/或-对外部动态源的神奇绑定(JRuby 或 JSON 是两个很好的例子)。

否则,发布的示例可以通过“匿名”类型和结构类型完全使用 Scala 中现有的静态类型来实现。无论如何,并不是说“动态”不方便(正如 0__ 指出的那样,即将到来——随意“走边”;-)。

考虑:

val dog = new {
   val name = "Rex"
   def speak = { "woof" }
}

val cat = new {
   val name = "Fluffy"
   def speak = { "meow" }
}

// Rock not shown here -- because it doesn't speak it won't compile
// with the following unless it stubs in. In both cases it's an error:
// the issue is when/where the error occurs.

def test(animal: { val name: String; def speak: String }) = {
   animal.name + " is telling " + animal.speak
}

// However, we can take in the more general type { val name: String } and try to
// invoke the possibly non-existent property, albeit in a hackish sort of way.
// Unfortunately pattern matching does not work with structural types AFAIK :(

val rock = new {
   val name = "Topaz"
}

def test2(animal: { val name: String }) = {
   animal.name + " is telling " + (try {
       animal.asInstanceOf[{ def speak: String }).speak
   } catch { case _ => "{very silently}" })
}

test(dog)
test(cat)
// test(rock) -- no! will not compile (a good thing)
test2(dog)
test2(cat)
test2(rock)

但是,这种方法很快就会变得很麻烦(要“添加”一个新属性,需要创建一个新类型并将当前数据复制到其中),并且部分利用了示例代码的简单性。也就是说,实际上不可能以这种方式创建真正的“开放”对象。在“开放”数据的情况下,在当前的 Scala (2.8) 实现中,各种 Map 可能是更好/可行的方法。

编码愉快。

【讨论】:

    【解决方案3】:

    首先,正如@pst 指出的那样,您的示例可以完全使用静态类型来实现,它不需要动态类型。

    其次,如果您想使用动态类型语言进行编程,请使用动态类型语言进行编程。

    话虽如此,您可以实际上在 Scala 中做类似的事情。这是一个简单的例子:

    class Dict[V](args: (String, V)*) extends Dynamic {
      import scala.collection.mutable.Map
    
      private val backingStore = Map[String, V](args:_*)
    
      def typed[T] = throw new UnsupportedOperationException()
    
      def applyDynamic(name: String)(args: Any*) = {
        val k = if (name.endsWith("_=")) name.dropRight(2) else name
        if (name.endsWith("_=")) backingStore(k) = args.first.asInstanceOf[V]
        backingStore.get(k)
      }
    
      override def toString() = "Dict(" + backingStore.mkString(", ") + ")"
    }
    
    object Dict {
      def apply[V](args: (String, V)*) = new Dict(args:_*)
    }
    
    val t1 = Dict[Any]()
    t1.bar_=("quux")
    
    val t2 = new Dict("foo" -> "bar", "baz" -> "quux")
    val t3 = Dict("foo" -> "bar", "baz" -> "quux")
    
    t1.bar // => Some(quux)
    t2.baz // => Some(quux)
    t3.baz // => Some(quux)
    

    如您所见,实际上您已经非常接近了。你的主要错误是 Dynamic 是一个特征,而不是一个类,所以你不能实例化它,你必须把它混合进去。你显然必须实际定义你想要它做什么,即实现 typedapplyDynamic

    如果您希望 您的 示例能够正常工作,则会遇到一些复杂情况。特别是,您需要类型安全的异构映射之类的东西作为后备存储。此外,还有一些语法方面的考虑。例如,foo.bar = baz 仅在 foo.bar_= 存在时才转换为 foo.bar_=(baz),但它不存在,因为 foo 是一个 Dynamic 对象。

    【讨论】:

    • @fernacolo:不,Dynamic 是 2.9 中的新功能。
    猜你喜欢
    • 2010-12-08
    • 2015-05-20
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    相关资源
    最近更新 更多