Scala中的结构类型调度

Scala中的结构类型调度,scala,Scala,我试图更好地掌握结构类型调度。例如,假设我有一个iterable对象,它有一个summary方法来计算平均值。因此o.summary()给出了列表的平均值。我可能想使用结构类型分派来启用summary(o) 关于o.summary()与summary(o),是否有一套最佳实践 如果我有一个方法summary(o:ObjectType)和summary(o:{def summary:Double}),scala如何解析summary(o) 结构类型分派与多方法或泛型函数有何不同 Michael G

我试图更好地掌握结构类型调度。例如,假设我有一个iterable对象,它有一个
summary
方法来计算平均值。因此
o.summary()
给出了列表的平均值。我可能想使用结构类型分派来启用
summary(o)

  • 关于
    o.summary()
    summary(o)
    ,是否有一套最佳实践
  • 如果我有一个方法
    summary(o:ObjectType)
    summary(o:{def summary:Double}),scala如何解析
    summary(o)
  • 结构类型分派与多方法或泛型函数有何不同
  • Michael Galpin给出了关于调度的信息:


    结构类型是Scala版本的“响应”式编程,在许多动态语言中都可以看到。很像

    def sayName ( x : { def name:String }){
        println(x.name)
    }
    
    然后,任何名为name的方法不带参数且返回字符串的对象都可以传递给sayName:

    case class Person(name:String)
    val dean = Person("Dean")
    sayName(dean) // Dean
    

    --
    1。在您的示例中,我不会使用
    summary(o)
    版本,因为这不是一种非常面向对象的编程风格。调用
    o.summary
    时(可以去掉括号,因为它没有副作用),您需要
    o
    summary
    属性。调用
    summary(o)
    时,将
    o
    传递给计算
    o
    的摘要的方法。我认为第一种方法更好:)

    我没有太多使用结构类型分派,但我认为它最适合(在大型系统中)只因为一个方法需要定义了某个方法的类型而必须编写接口的情况。有时,创建该接口并强制客户机实现它可能会很尴尬。有时,您希望使用另一个API中定义的客户机,该API符合您的接口,但没有显式地实现它。因此,在我看来,结构类型分派是隐式生成适配器模式的一种很好的方法(保存在样板文件中,耶!)

    --
    2。显然,如果您调用
    summary(o)
    并且
    o
    属于
    ObjectType
    summary(o:ObjectType)
    将被调用(这是有意义的)。如果调用
    summary(bar)
    ,其中
    bar
    不是
    ObjectType
    ,则可能发生两种情况。如果
    bar
    具有正确签名和名称的方法
    summary()
    ,调用将编译,否则调用将不编译

    例如:

    scala> case class ObjectType(summary: Double)
    defined class ObjectType
    
    scala> val o = ObjectType(1.2)
    o: ObjectType = ObjectType(1.2)
    
    scala> object Test {
         | def summary(o: ObjectType)  { println("1") }
         | def summary(o: { def summary: Double}) { println("2")}
         | }
    defined module Test
    
    scala> Test.summary(o)
    1
    
    不幸的是,由于类型擦除,以下内容无法编译:

    scala> object Test{
         | def foo(a: {def a: Int}) { println("A") }
         | def foo(b: {def b: Int}) { println("B") }
         | }
    :6: error: double definition:
    method foo:(AnyRef{def b(): Int})Unit and
    method foo:(AnyRef{def a(): Int})Unit at line 5
    have same type after erasure: (java.lang.Object)Unit
           def foo(b: {def b: Int}) { println("B") }
    
    --
    3。从某种意义上说,结构类型分派比泛型方法更具动态性,也有不同的用途。在一般方法中,你可以说:a。我想要任何类型的东西;B我想要某种类型的东西,它是a的一个子类型;C我要一个B的超型;D我将采用隐式转换为C类型的方法。所有这些都比“我想要一个具有正确签名的方法
    foo
    的类型”严格得多。此外,结构类型分派确实使用反射,因为它们是通过类型擦除实现的

    我对多方法知之甚少,但看看下面的例子,Scala中的多方法似乎可以通过模式匹配来实现。例如:

    def collide(a: Collider, b: Collider) = (a, b) match {
        case (asteroid: Asteroid, spaceship: Spaceship) => // ...
        case (asteroid1: Asteroid, asteroid2: Asteroid) => // ...
    ... 
    
    同样,您可以使用结构类型dispatch-
    defclide(a:{def processCollision()})
    ,但这取决于设计决策(在本例中,我将创建一个接口)


    --Flaviu-Cipcigan

    结构数据类型并不是那么有用。这并不是说它们毫无用处,但它们绝对是一个利基的东西

    例如,您可能想为某个东西的“
    大小”
    ”编写一个通用测试用例。您可以这样做:

    def hasSize(o: { def size: Int }, s: Int): Boolean = {
      o.size == s
    }
    
    然后,这可以用于实现“size”方法的任何对象,无论其类层次结构如何

    现在,它们不是结构类型调度。它们与分派无关,而是与类型定义有关


    Scala始终是一种面向对象的语言。必须对对象调用方法。函数调用实际上是“
    apply
    ”方法调用。像“
    println
    ”这样的东西只是导入范围的对象的成员。

    我想你问过Scala对结构类型的调用做了什么。它使用反射。例如,考虑

    def repeat(x: { def quack(): Unit }, n: Int) {
       for (i <- 1 to n) x.quack()
    }
    
    def repeat(x:{def-quack():Unit},n:Int){
    
    对于(谢谢,这很有帮助。在最后一点上,我相信多方法会避免使用case/switch类型语句,因为使用collide的所有类型都必须由api设计器知道。