diff --git a/_zh-cn/overviews/scala3-book/ca-given-using-clauses.md b/_zh-cn/overviews/scala3-book/ca-given-using-clauses.md index 4d6eed12fe..f6c56c3897 100644 --- a/_zh-cn/overviews/scala3-book/ca-given-using-clauses.md +++ b/_zh-cn/overviews/scala3-book/ca-given-using-clauses.md @@ -1,5 +1,5 @@ --- -title: Given Instances and Using Clauses +title: Given 实例和 Using 语句 type: section description: This page demonstrates how to use 'given' instances and 'using' clauses in Scala 3. num: 59 @@ -12,16 +12,24 @@ layout: multipage-overview permalink: "/zh-cn/scala3/book/:title.html" --- -Scala 3 offers two important feature for contextual abstraction: -- **Using Clauses** allow you to specify parameters that, at the call site, can be omitted by the programmer and should be automatically provided by the context. -- **Given Instances** let you define terms that can be used by the Scala compiler to fill in the missing arguments. +
使用上下文抽象仅限Scala 3
-## Using Clauses -When designing a system, often context information like _configuration_ or settings need to be provided to the different components of your system. -One common way to achieve this is by passing the configuration as additional argument to your methods. +Scala 3 提供了两个重要的上下文抽象特性: + +- **Using 语句** 允许你指定参数,这些参数程序员可以在调用时省略,这些参数由上下文自动提供。 +- **Given 实例** 让您定义 Scala 编译器可以用来填充缺失参数的术语。 + +## Using 语句 + +在设计系统时,通常需要向系统的不同组件提供上下文信息,如_配置_或设置。 +实现此目的的一种常见方法是将配置作为附加参数传递给您的方法。 + +在下面的示例中,我们定义了一个样例类 `Config` 来模拟一些网站配置并在不同的方法中传递它。 + +{% tabs nonusing %} +{% tab 'Scala 2 and 3' %} -In the following example, we define a case class `Config` to model some website configuration and pass it around in the different methods. ```scala case class Config(port: Int, baseUrl: String) @@ -33,11 +41,20 @@ def renderWidget(items: List[String], c: Config): String = ??? val config = Config(8080, "docs.scala-lang.org") renderWebsite("/home", config) ``` -Let us assume that the configuration does not change throughout most of our code base. -Passing `c` to each and every method call (like `renderWidget`) becomes very tedious and makes our program more difficult to read, since we need to ignore the `c` argument. -#### Using `using` to mark parameters as contextual -In Scala 3, we can mark some of the parameters of our methods as _contextual_. +{% endtab %} +{% endtabs %} + +让我们假设配置在我们的大部分代码库中都没有改变。 +将 `c` 传递给每个方法调用(如 `renderWidget`)变得非常乏味并且使我们的程序更难阅读,因为我们需要忽略 `c` 参数。 + +#### 使用 `using` 将参数标记为上下文 + +在 Scala 3 中,我们可以将方法的一些参数标记为_上下文_。 + +{% tabs using1 %} +{% tab 'Scala 3 Only' %} + ```scala def renderWebsite(path: String)(using c: Config): String = "" + renderWidget(List("cart")) + "" @@ -46,13 +63,20 @@ def renderWebsite(path: String)(using c: Config): String = def renderWidget(items: List[String])(using c: Config): String = ??? ``` -By starting a parameter section with the keyword `using`, we tell the Scala compiler that at the callsite it should automatically find an argument with the correct type. -The Scala compiler thus performs **term inference**. -In our call to `renderWidget(List("cart"))` the Scala compiler will see that there is a term of type `Config` in scope (the `c`) and automatically provide it to `renderWidget`. -So the program is equivalent to the one above. +{% endtab %} +{% endtabs %} + +通过使用关键字 `using` 开始参数部分,我们告诉 Scala 编译器它应该在调用处自动找到具有正确类型的参数。 +因此,Scala 编译器执行**术语推断**。 + +在我们对 `renderWidget(List("cart"))` 的调用中,Scala 编译器将看到作用域(`c`)中有一个类型为 `Config` 的术语,并自动将其提供给 `renderWidget`。 +所以程序等同于上面的程序。 -In fact, since we do not need to refer to `c` in our implementation of `renderWebsite` anymore, we can even omit its name in the signature: +事实上,由于我们不再需要在 `renderWebsite` 的实现中引用 `c`,我们甚至可以在签名中省略它的名字: + +{% tabs using2 %} +{% tab 'Scala 3 Only' %} ```scala // no need to come up with a parameter name @@ -61,22 +85,37 @@ def renderWebsite(path: String)(using Config): String = "" + renderWidget(List("cart")) + "" ``` -#### Explicitly providing contextual arguments -We have seen how to _abstract_ over contextual parameters and that the Scala compiler can provide arguments automatically for us. -But how can we specify which configuration to use for our call to `renderWebsite`? +{% endtab %} +{% endtabs %} + +#### 明确提供上下文参数 + +我们已经了解了如何_抽象_上下文参数,并且 Scala 编译器可以自动为我们提供参数。 +但是我们如何指定调用 `renderWebsite` 时使用的配置呢? -Like we specified our parameter section with `using`, we can also explicitly provide contextual arguments with `using:` +就像我们使用 `using` 指定参数部分一样,我们也可以使用 `using` 显式提供上下文参数: + +{% tabs using3 %} +{% tab 'Scala 3 Only' %} ```scala renderWebsite("/home")(using config) ``` -Explicitly providing contextual parameters can be useful if we have multiple different values in scope that would make sense and we want to make sure that the correct one is passed to the function. -For all other cases, as we will see in the next Section, there is also another way to bring contextual values into scope. +{% endtab %} +{% endtabs %} + +如果我们在范围内有多个有意义的不同值,并且我们希望确保将正确的值传递给函数,则显式提供上下文参数可能很有用。 + +对于所有其他情况,正如我们将在下一节中看到的,还有另一种方法可以将上下文值引入范围。 -## Given Instances -We have seen that we can explicitly pass arguments as contextual parameters by marking the argument section of the _call_ with `using`. -However, if there is _a single canonical value_ for a particular type, there is another preferred way to make it available to the Scala compiler: by marking it as `given`. +## Give 实例 + +我们已经看到,我们可以通过使用 `using` 标记 _调用_的参数部分来显式地将参数作为上下文参数传递。 +但是,如果某个特定类型有一个_单一的规范值_,则还有另一种首选方法可以使其对 Scala 编译器可用:将其标记为 `given`。 + +{% tabs given1 %} +{% tab 'Scala 3 Only' %} ```scala val config = Config(8080, "docs.scala-lang.org") @@ -88,9 +127,16 @@ given Config = config // this is the value the Scala compiler will infer // as argument to contextual parameters of type Config ``` -In the above example we specify that whenever a contextual parameter of type `Config` is omitted in the current scope, the compiler should infer `config` as an argument. -Having defined a given for `Config`, we can simply call `renderWebsite`: +{% endtab %} +{% endtabs %} + +在上面的示例中,我们指定每当在当前范围内省略 `Config` 类型的上下文参数时,编译器应该将 `config` 推断为参数。 + +为 `Config` 定义了 given,我们可以简单地调用 `renderWebsite`: + +{% tabs given2 %} +{% tab 'Scala 3 Only' %} ```scala renderWebsite("/home") @@ -98,5 +144,8 @@ renderWebsite("/home") // again no argument ``` +{% endtab %} +{% endtabs %} + [reference]: {{ site.scala3ref }}/overview.html [blog-post]: /2020/11/06/explicit-term-inference-in-scala-3.html