【问题标题】:Scala: how to inherit a "static slot"?Scala:如何继承“静态插槽”?
【发布时间】:2009-10-19 02:52:50
【问题描述】:

嗯,我正在学习 Scala,所以这个问题对大多数人来说可能太基础了。

在 Java 中,我可以在一个类中拥有一个静态槽(函数或变量),然后我也会在继承的类中拥有该槽。

在 Scala 中,我没有静态插槽,但我有伴随对象。但是我发现这些对象不是继承类的一部分,所以如果我有两个类 PersonStudent,并且 Person 有一个带有变量 all:List 的伴随对象,它返回一个所有人的列表所以我可以做Person.all,我期待我也可以做Student.all,但事实并非如此。

有什么方法可以让我在 java 中获得相同的行为?

谢谢!

【问题讨论】:

    标签: inheritance scala static


    【解决方案1】:

    从理论上讲,Java 在这方面的行为是非常坏的。从面向对象的角度来看,子类继承静态成员这一事实确实没有任何意义。静态实际上只不过是花哨的、作用域的全局变量。继承是您在类级别看到的东西,但静态实际上不在类级别(因为它们是全局的),因此不应应用继承。它在 Java 中的表现……令人不安。

    Scala 在这个部门确实走上了正轨;我们都应该感激的事情。正如另一个答案中提到的,定义“继承”静态的正确方法是将继承的成员提取到特征中:

    trait Inherited {
      def foo() { ... }
      def bar(i: Int) = ...
    }
    
    class Person {
      ...
    }
    
    object Person extends Inherited
    
    class Student extends Person {
      ...
    }
    
    object Student extends Inherited
    

    它可能看起来比 Java 更冗长,但相信我,当我说它的语义并不那么令人惊讶时。

    【讨论】:

      【解决方案2】:

      我不知道这是否是您的意思,但伴生对象可以从某些特征/类扩展:

      class Person
      class Student extends Person
      
      trait Aggregation[T] {
        val all: List[T]
      }
      
      object Person extends Aggregation[Person] {
        val all: List[Person] = List(new Person, new Person)
      }
      
      object Student extends Aggregation[Student] {
        val all: List[Student] = List(new Student, new Student)
      }
      
      println(Person.all) // prints all persons
      println(Student.all) // prints all students
      

      【讨论】:

        【解决方案3】:

        Scala 中的对象不像 Java 中的静态那样是类级实体。它们只是一个类定义和单例实例化合二为一。

        伴生对象是一种特殊情况,它允许在它与其伴生类之间共享私有数据。

        对象可以扩展类,但不能扩展其他对象。毕竟“对象”只是一个单例实例——“对象”的类定义是隐藏的。

        期望伴随对象和伴随类之间的特殊关系在伴随对象上投射额外的类层次结构是否合理?

        我怀疑在 Person 和 Student 之间实现依赖的最佳方法是委托。

        object Person { val all = List(1,2,3) }
        object Student { val all = Person.all.filter(_ % 2 == 0) }
        

        【讨论】:

          【解决方案4】:

          Afaics、Daniel Spiewak 和 Walter Chang 的答案似乎提供了 all 列表的两个单独副本。我没有测试以下内容,但我希望即使有错误也能提供正确的大纲。

          class Person
          class Student extends Person
          
          object Person {
            val all: List[Person]
          }
          

          然后在Student 内,通过Person.all 访问

          如果您想通过Student.all 提供访问权限,那么

          object Student {
            def all() = Person.all
          }
          

          另一种方法是允许您在要继承的特征中声明静态(即单例对象)。

          trait StaticAll {
             object Static { val all: List[Person] }
          }
          
          class Person extends StaticAll
          class Student extends Person
          

          然后使用StaticAll#Static.all 访问。我认为这是正确的,而不是StaticAll.Static.all。同样,这一切都在我的脑海中,我没有测试任何这个。请纠正我的错误。

          【讨论】:

          • 错误是列表有两个单独的副本。事实是,all 不是一个列表,而是一个参考。不客气。
          • 写这篇评论时,我对 Scala 还很陌生。我现在意识到 Walter Chang 的特征声明了一个未初始化的引用,因此他的代码没有列表的 2 个副本。在我的代码中,我忘记初始化 val List[Person] = List()。通过这种更改,我的代码是否正确?
          猜你喜欢
          • 1970-01-01
          • 2021-08-23
          • 2023-03-14
          • 1970-01-01
          • 2017-02-07
          • 2018-02-25
          • 1970-01-01
          • 1970-01-01
          • 2022-01-23
          相关资源
          最近更新 更多