【问题标题】:Why does the Scala API have two strategies for organizing types?为什么 Scala API 有两种组织类型的策略?
【发布时间】:2011-07-16 18:16:52
【问题描述】:

我注意到 Scala 标准库使用两种不同的策略来组织类、特征和单例对象。

  1. 使用其成员为其导入的包。例如,这就是您访问scala.collection.mutable.ListBuffer 的方式。这种技术来自 Java、Python 等。

  2. 使用特征的类型成员。例如,这就是您访问Parser 类型的方式。你首先需要混入scala.util.parsing.combinator.Parsers。这种技术来自 Java、Python 等并不熟悉,并且在第三方库中使用得不多。

我想 (2) 的一个优点是它可以组织方法和类型,但是根据 Scala 2.8 的包对象,使用 (1) 也可以做到这一点。为什么有这两种策略?什么时候应该使用它们?

【问题讨论】:

    标签: scala import packages traits


    【解决方案1】:

    这里注意的命名是path-dependent types。这就是你所说的第二个选项,我只谈它。除非你碰巧有一个问题被它解决了,否则你应该总是选择 1 号选项。

    您错过的是Parser 类引用了Parsers 类中定义的内容。事实上,Parser 类本身依赖于 inputParsers 上定义的内容:

    abstract class Parser[+T] extends (Input => ParseResult[T])
    

    Input 类型定义如下:

    type Input = Reader[Elem]
    

    Elem 是抽象的。例如,考虑RegexParsersTokenParsers。前者将Elem定义为Char,而后者将其定义为Token。这意味着每个人的Parser 是不同的。更重要的是,因为ParserParsers 的子类,Scala 编译器将确保在编译时您不会将RegexParsersParser 传递给TokenParsers,反之亦然。事实上,您甚至无法将RegexParsers 的一个实例的Parser 传递给它的另一个实例。

    【讨论】:

      【解决方案2】:

      第二个也称为Cake pattern。 这样做的好处是,类中混入了特征的代码变得独立于该特征中方法和类型的特定实现。它允许在不知道具体实现的情况下使用 trait 的成员。

      trait Logging {
        def log(msg: String)
      }
      
      trait App extends Logging {
        log("My app started.")
      }
      

      上面,Logging trait 是App 的需求(需求也可以用自类型表示)。然后,在您的应用程序中的某个时刻,您可以决定实现是什么,并将实现特征混合到具体的类中。

      trait ConsoleLogging extends Logging {
        def log(msg: String) = println(msg)
      }
      
      object MyApp extends App with ConsoleLogging
      

      这比导入有优势,因为您的代码段的要求不受import 语句定义的实现的约束。此外,它还允许您构建和分发 API,该 API 可以在其他地方的不同构建中使用,前提是通过混合具体实现来满足其要求。

      但是,使用此模式时需要注意一些事项。

      1. 在 trait 中定义的所有类都将引用外部类。这可能是一个涉及性能的问题,或者当您使用序列化时(当外部类不可序列化时,或者更糟糕的是,如果是,但您不希望它被序列化)。
      2. 如果您的“模块”变得非常大,您将拥有一个非常大的特征和一个非常大的源文件,或者必须将模块特征代码分布在多个文件中。这可能会导致一些样板文件。
      3. 它可能会迫使您必须使用此范例编写整个应用程序。在不知不觉中,每个课程都必须混合其要求。
      4. 除非您使用某种手写委托,否则必须在编译时知道具体实现。您不能根据运行时可用的值动态混合实现特征。

      我猜图书馆设计者并没有将上述任何一个问题视为Parsers 所关注的问题。

      【讨论】:

      • 这是一个很好的答案,但是对于另一个问题。这里的设计目标与蛋糕图案完全无关。
      • 您是对的-您的答案中有关Parsers 的注释更详细。但是,他确实询问了何时应该使用这些导入策略。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 2017-01-23
      相关资源
      最近更新 更多