gpt4 book ai didi

scala - 什么是 Scala 中的一流模块?

转载 作者:行者123 更新时间:2023-12-04 03:27:04 25 4
gpt4 key购买 nike

说 Scala 通过对象语法提供一流的模块支持是什么意思?词汇表中甚至没有提到这个短语,但我现在已经遇到了两次并且无法破译它。是在 this 中说的关于适配器的博客文章。

最佳答案

“模块”是可插拔的软件,有时也称为“包”。它通过一组定义良好的接口(interface)提供功能,这些接口(interface)声明了它提供了什么以及它需要什么。最后,它是可以互换的。

很少有语言直接支持模块,主要是因为虽然支持声明 API 很常见,但支持声明依赖项或需求并不常见。流行语言中的库通常依赖于“标准”库提供的类型,或者需要使用实现它们提供的 API 的对象进行初始化。

所以,如果我想制作一个基准模块,我通常会求助于标准库提供的时钟设施,或者更糟的是,我会声明一个时钟类型并请求在模块功能之前用一个实现它的类进行初始化可以使用了。

但是,当模块支持可用时,我不仅会声明我提供的基准测试接口(interface),还会声明我需要一个“时钟模块”——一个导出我需要的某些接口(interface)的模块。

我的模块的客户端不需要做任何事情来使用我的接口(interface)——它可以继续使用它。或者它甚至不能声明我的基准模块将被使用,而是声明它需要一个基准模块。

只有在“顶级”级别,应用程序级别(模块是应用程序的组件)才能满足需求。那时它会声明它将使用该客户端、我的基准测试和一个实现我的时钟要求的模块。

如果您了解 Guice,这可能看起来很熟悉。 Guice 解决的问题在很大程度上是由于 Java 编程语言中缺乏模块支持造成的。

所以,回到 Scala。模块支持如何工作?好吧,我的模块的界面可能如下所示:

trait Benchmark extends Clock // What I need {
// What I provide
type ABench <: Bench
trait Bench {
def measure(task: => Unit): Long
}
def aBench: ABench
}

和 Clock 将是一个模块定义,例如:
trait Clock {
// What it provides
type AClock <: Clock
trait Clock {
def now(): Long
}
def aClock: AClock
}

我的模块本身可能如下所示:
trait MyModule extends Benchmark {
class ABench extends Bench {
def measure(task: => Unit): Long = {
val measurements = for(_ <- 1 to 10) yield {
val start = aClock.now()
task
val end = aClock.now()
end - start
}
measurements / 10
}
}
object aBench extends ABench
}

时钟模块的定义类似。应用程序可以声明为模块的组合:
trait application extends Clock with Benchmark with ...

当然,依赖项不需要声明,因为它们已经提供了。然后,您可以组合提供构建应用程序要求的模块:
object Application extends MyModule with JavaClock with ...

这会将 MyModule 的需求与 JavaClock 提供的实现联系起来。上面的东西仍然需要一些共享知识,因为“时钟”可能是我提供的 API。当然,您可以编写代理,但它不是即插即用的。如果我像这样声明我的 Benchmark 模块,Scala 可以走得更远:
trait Benchmark {
type Clock = {
def now(): Long
}
def aClock: Clock

// What I provide
type ABench <: Bench
trait Bench {
def measure(task: => Unit): Long
}
def aBench: ABench
}

现在任何提供 now(): Long 方法的类都可以用来满足要求,无需任何桥接。当然,如果方法的名称是“millis(): Long”而不是“now(): Long”,我仍然被搞砸了,这种“绑定(bind)”是提供模块支持的语言可能会解决的问题,虽然不是 Scala。此外,由于 JVM 的工作方式,也存在性能损失。

所以,这就是模块和模块支持。最后是一流的模块。对 X 的一流支持意味着 X 可以作为值进行操作。例如,Scala 对函数有一流的支持,这意味着我可以将函数传递给方法,将其存储在变量、映射等中。

对模块的第一类支持基本上是实例化,尽管可以使用“对象”来创建该模块的单例,然后将其传递出去(我将在下面进一步讨论其优点)。所以,我可以这样做:
object myBenchmark extends MyModule with JVMClock

并将 myBenchmark 作为参数传递给需要此类模块的方法。

Scala 中有两个元素可以完成所有这些工作:抽象类型和路径依赖类型。

抽象类型,即“类型”声明,使得一段代码可以声明它将使用类型 X,它不会由谁调用或实例化它来定义,而是在模块获得的那一刻组成。

路径依赖类型使得在不完全不安全的情况下使用模块成为可能,但又不会限制到不允许任何东西。假设我这样做:
val b: MyModule.Clock = MyModule.aClock

假设我在 Benchmark 上有一个将时钟作为参数的方法。我可以在 MyModule 上调用该方法,将 b 作为参数传递,因为 Scala 知道 b 的时钟是绑定(bind)到 MyModule 的时钟。如果我尝试将 b 传递给另一个实现 Benchmark 的模块,Scala 不会让我这样做。也就是说,我可以从 Benchmark 中获取特定于 Benchmark 抽象类型的值——除了模块实现之外的所有人都不知道——并将其反馈给该 Benchmark 而不是其他 Benchmark 实现。

关于scala - 什么是 Scala 中的一流模块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29529252/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com