diff --git a/_overviews/scala3-book/packaging-imports.md b/_overviews/scala3-book/packaging-imports.md index 6cd3835078..56f3e86194 100644 --- a/_overviews/scala3-book/packaging-imports.md +++ b/_overviews/scala3-book/packaging-imports.md @@ -21,24 +21,25 @@ With Scala you can: These features are demonstrated in the following examples. - - ## Creating a package Packages are created by declaring one or more package names at the top of a Scala file. For example, when your domain name is _acme.com_ and you’re working in the _model_ package of an application named _myapp_, your package declaration looks like this: +{% tabs packaging-imports-1 %} +{% tab 'Scala 2 and 3' %} ```scala package com.acme.myapp.model class Person ... ``` +{% endtab %} +{% endtabs %} By convention, package names should be all lower case, and the formal naming convention is *\.\.\.\*. Although it’s not required, package names typically follow directory structure names, so if you follow this convention, a `Person` class in this project will be found in a *MyApp/src/main/scala/com/acme/myapp/model/Person.scala* file. - ### Using multiple packages in the same file The syntax shown above applies to the entire source file: all the definitions in the file @@ -48,6 +49,22 @@ at the beginning of the file. Alternatively, it is possible to write package clauses that apply only to the definitions they contain: +{% tabs packaging-imports-1 class=tabs-scala-version %} +{% tab 'Scala 2' %}```scala +package users { + + package administrators { // the full name of this package is users.administrators + class AdminUser // the full name of this class users.administrators.AdminUser + } + package normalusers { // the full name of this package is users.normalusers + class NormalUser // the full name of this class is users.normalusers.NormalUser + } +} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-1 %} + ```scala package users: @@ -57,14 +74,14 @@ package users: package normalusers: // the full name of this package is users.normalusers class NormalUser // the full name of this class is users.normalusers.NormalUser ``` +{% endtab %} +{% endtabs %} Note that the package names are followed by a colon, and that the definitions within a package are indented. The advantages of this approach are that it allows for package nesting, and provides more obvious control of scope and encapsulation, especially within the same file. - - ## Import statements, Part 1 Import statements are used to access entities in other packages. @@ -76,12 +93,27 @@ Import statements fall into two main categories: If you’re used to a language like Java, the first class of import statements is similar to what Java uses, with a slightly different syntax that allows for more flexibility. These examples demonstrate some of that flexibility: -```` +{% tabs packaging-imports-2 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import users._ // import everything from the `users` package +import users.User // import only the `User` class +import users.{User, UserPreferences} // import only two selected members +import users.{UserPreferences => UPrefs} // rename a member as you import it +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-2 %} + +```scala import users.* // import everything from the `users` package import users.User // import only the `User` class import users.{User, UserPreferences} // import only two selected members import users.{UserPreferences as UPrefs} // rename a member as you import it -```` +``` + +{% endtab %} +{% endtabs %} Those examples are meant to give you a taste of how the first class of `import` statements work. They’re explained more in the subsections that follow. @@ -93,90 +125,165 @@ A note before moving on: > Import clauses are not required for accessing members of the same package. - - ### Importing one or more members In Scala you can import one member from a package like this: +{% tabs packaging-imports-3 %} +{% tab 'Scala 2 and 3' %} ```scala import scala.concurrent.Future ``` +{% endtab %} +{% endtabs %} and multiple members like this: +{% tabs packaging-imports-4 %} +{% tab 'Scala 2 and 3' %} ```scala import scala.concurrent.Future import scala.concurrent.Promise import scala.concurrent.blocking ``` +{% endtab %} +{% endtabs %} When importing multiple members, you can import them more concisely like this: +{% tabs packaging-imports-5 %} +{% tab 'Scala 2 and 3' %} ```scala import scala.concurrent.{Future, Promise, blocking} ``` +{% endtab %} +{% endtabs %} When you want to import everything from the *scala.concurrent* package, use this syntax: +{% tabs packaging-imports-6 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import scala.concurrent._ +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-6 %} + ```scala import scala.concurrent.* ``` +{% endtab %} +{% endtabs %} ### Renaming members on import Sometimes it can help to rename entities when you import them to avoid name collisions. For instance, if you want to use the Scala `List` class and also the *java.util.List* class at the same time, you can rename the *java.util.List* class when you import it: +{% tabs packaging-imports-7 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{List => JavaList} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-7 %} + ```scala import java.util.{List as JavaList} ``` +{% endtab %} +{% endtabs %} Now you use the name `JavaList` to refer to that class, and use `List` to refer to the Scala list class. You can also rename multiple members at one time using this syntax: +{% tabs packaging-imports-8 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{Date => JDate, HashMap => JHashMap, _} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-8 %} + ```scala import java.util.{Date as JDate, HashMap as JHashMap, *} ``` -That line of code says, “Rename the `Date` and `HashMap` classes as shown, and import everything else in the _java.util_ package without renaming any other members.” +{% endtab %} +{% endtabs %} +That line of code says, “Rename the `Date` and `HashMap` classes as shown, and import everything else in the _java.util_ package without renaming any other members.” ### Hiding members on import You can also *hide* members during the import process. This `import` statement hides the *java.util.Random* class, while importing everything else in the *java.util* package: +{% tabs packaging-imports-9 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{Random => _, _} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-9 %} + ```scala import java.util.{Random as _, *} ``` +{% endtab %} +{% endtabs %} If you try to access the `Random` class it won’t work, but you can access all other members from that package: +{% tabs packaging-imports-10 %} +{% tab 'Scala 2 and 3' %} ```scala val r = new Random // won’t compile new ArrayList // works ``` +{% endtab %} +{% endtabs %} #### Hiding multiple members To hide multiple members during the import process, list them before using the final wildcard import: +{% tabs packaging-imports-11 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{List => _, Map => _, Set => _, _} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-11 %} + ```scala scala> import java.util.{List as _, Map as _, Set as _, *} ``` +{% endtab %} +{% endtabs %} Once again those classes are hidden, but you can use all other classes in *java.util*: +{% tabs packaging-imports-12 %} +{% tab 'Scala 2 and 3' %} ```scala scala> new ArrayList[String] val res0: java.util.ArrayList[String] = [] ``` +{% endtab %} +{% endtabs %} Because those Java classes are hidden, you can also use the Scala `List`, `Set`, and `Map` classes without having a naming collision: +{% tabs packaging-imports-13 %} +{% tab 'Scala 2 and 3' %} ```scala scala> val a = List(1, 2, 3) val a: List[Int] = List(1, 2, 3) @@ -187,13 +294,32 @@ val b: Set[Int] = Set(1, 2, 3) scala> val c = Map(1 -> 1, 2 -> 2) val c: Map[Int, Int] = Map(1 -> 1, 2 -> 2) ``` - +{% endtab %} +{% endtabs %} ### Use imports anywhere In Scala, `import` statements can be anywhere. They can be used at the top of a source code file: +{% tabs packaging-imports-14 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +package foo + +import scala.util.Random + +class ClassA { + def printRandom(): Unit = { + val r = new Random // use the imported class + // more code here... + } +} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-14 %} + ```scala package foo @@ -204,9 +330,33 @@ class ClassA: val r = new Random // use the imported class // more code here... ``` +{% endtab %} +{% endtabs %} You can also use `import` statements closer to the point where they are needed, if you prefer: +{% tabs packaging-imports-15 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +package foo + +class ClassA { + import scala.util.Random // inside ClassA + def printRandom(): Unit = { + val r = new Random + // more code here... + } +} + +class ClassB { + // the Random class is not visible here + val r = new Random // this code will not compile +} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-15 %} + ```scala package foo @@ -221,6 +371,8 @@ class ClassB: val r = new Random // this code will not compile ``` +{% endtab %} +{% endtabs %} ### “Static” imports @@ -228,19 +380,43 @@ When you want to import members in a way similar to the Java “static import” Use this syntax to import all static members of the Java `Math` class: +{% tabs packaging-imports-16 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.lang.Math._ +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-16 %} + ```scala import java.lang.Math.* ``` +{% endtab %} +{% endtabs %} Now you can access static `Math` class methods like `sin` and `cos` without having to precede them with the class name: +{% tabs packaging-imports-17 class=tabs-scala-version %} +{% tab 'Scala 2' %} ```scala -import java.lang.Math.* +import java.lang.Math._ val a = sin(0) // 0.0 val b = cos(PI) // -1.0 ``` +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-17 %} + +```scala +import java.lang.Math.* + +val a = sin(0) // 0.0 +val b = cos(PI) // -1.0 +``` +{% endtab %} +{% endtabs %} ### Packages imported by default @@ -253,25 +429,36 @@ The members of the Scala object `Predef` are also imported by default. > If you ever wondered why you can use classes like `List`, `Vector`, `Map`, etc., without importing them, they’re available because of definitions in the `Predef` object. - - ### Handling naming conflicts In the rare event there’s a naming conflict and you need to import something from the root of the project, prefix the package name with `_root_`: -``` +{% tabs packaging-imports-18 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala package accounts -import _root_.accounts.* +import _root_.accounts._ ``` +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-18 %} + +```scala +package accounts +import _root_.accounts.* +``` +{% endtab %} +{% endtabs %} ## Importing `given` instances -As you’ll see in the [Contextual Abstractions][contextual] chapter, a special form of the `import` statement is used to import `given` instances. +As you’ll see in the [Contextual Abstractions][contextual] chapter, in Scala 3 a special form of the `import` statement is used to import `given` instances. The basic form is shown in this example: +{% tabs packaging-imports-19 %} +{% tab 'Scala 3 only' %} ```scala object A: class TC @@ -282,16 +469,22 @@ object B: import A.* // import all non-given members import A.given // import the given instance ``` +{% endtab %} +{% endtabs %} In this code, the `import A.*` clause of object `B` imports all members of `A` *except* the `given` instance `tc`. Conversely, the second import, `import A.given`, imports *only* that `given` instance. The two `import` clauses can also be merged into one: +{% tabs packaging-imports-20 %} +{% tab 'Scala 3 only' %} ```scala object B: import A.{given, *} ``` - +{% endtab %} +{% endtabs %} +In Scala 2, that style of import does not exist. Implicit definitions are always imported by the wildcard import. ### Discussion The wildcard selector `*` brings all definitions other than givens or extensions into scope, whereas a `given` selector brings all *givens*---including those resulting from extensions---into scope. @@ -303,26 +496,35 @@ These rules have two main benefits: - It enables importing all givens without importing anything else. This is particularly important since givens can be anonymous, so the usual use of named imports is not practical. - ### By-type imports Since givens can be anonymous, it’s not always practical to import them by their name, and wildcard imports are typically used instead. *By-type imports* provide a more specific alternative to wildcard imports, which makes it more clear what is imported: +{% tabs packaging-imports-21 %} +{% tab 'Scala 3 only' %} ```scala import A.{given TC} ``` +{% endtab %} +{% endtabs %} This imports any `given` in `A` that has a type which conforms to `TC`. Importing givens of several types `T1,...,Tn` is expressed by multiple `given` selectors: +{% tabs packaging-imports-22 %} +{% tab 'Scala 3 only' %} ```scala import A.{given T1, ..., given Tn} ``` +{% endtab %} +{% endtabs %} Importing all `given` instances of a parameterized type is expressed by wildcard arguments. For example, when you have this `object`: +{% tabs packaging-imports-23 %} +{% tab 'Scala 3 only' %} ```scala object Instances: given intOrd as Ordering[Int] @@ -330,26 +532,38 @@ object Instances: given ec as ExecutionContext = ... given im as Monoid[Int] ``` +{% endtab %} +{% endtabs %} This import statement imports the `intOrd`, `listOrd`, and `ec` instances, but leaves out the `im` instance because it doesn’t fit any of the specified bounds: +{% tabs packaging-imports-24 %} +{% tab 'Scala 3 only' %} ```scala import Instances.{given Ordering[?], given ExecutionContext} ``` +{% endtab %} +{% endtabs %} By-type imports can be mixed with by-name imports. If both are present in an import clause, by-type imports come last. For instance, this import clause imports `im`, `intOrd`, and `listOrd`, but leaves out `ec`: +{% tabs packaging-imports-25 %} +{% tab 'Scala 3 only' %} ```scala import Instances.{im, given Ordering[?]} ``` - +{% endtab %} +{% endtabs %} ### An example As a concrete example, imagine that you have this `MonthConversions` object that contains two `given` definitions: +{% tabs packaging-imports-26 %} +{% tab 'Scala 3 only' %} + ```scala object MonthConversions: trait MonthConverter[A]: @@ -369,31 +583,46 @@ object MonthConversions: case "feb" => "February" // more cases here ... ``` +{% endtab %} +{% endtabs %} To import those givens into the current scope, use these two `import` statements: +{% tabs packaging-imports-27 %} +{% tab 'Scala 3 only' %} + ```scala import MonthConversions.* import MonthConversions.{given MonthConverter[?]} ``` +{% endtab %} +{% endtabs %} Now you can create a method that uses those `given` instances: +{% tabs packaging-imports-28 %} +{% tab 'Scala 3 only' %} + ```scala def genericMonthConverter[A](a: A)(using monthConverter: MonthConverter[A]): String = monthConverter.convert(a) ``` +{% endtab %} +{% endtabs %} Then you can use that method in your application: +{% tabs packaging-imports-29 %} +{% tab 'Scala 3 only' %} + ```scala @main def main = println(genericMonthConverter(1)) // January println(genericMonthConverter("jan")) // January ``` +{% endtab %} +{% endtabs %} As mentioned, one of the key design benefits of the “import given” syntax is to make it clear where givens in scope come from, and it’s clear in these `import` statements that the givens come from the `MonthConversions` object. - - [contextual]: {% link _overviews/scala3-book/ca-contextual-abstractions-intro.md %} diff --git a/_zh-cn/overviews/scala3-book/packaging-imports.md b/_zh-cn/overviews/scala3-book/packaging-imports.md index b121f8b99c..4ef39fbf1a 100644 --- a/_zh-cn/overviews/scala3-book/packaging-imports.md +++ b/_zh-cn/overviews/scala3-book/packaging-imports.md @@ -31,11 +31,15 @@ Scala 导入成员的方法也类似于 Java,并且更灵活。 通过在 Scala 文件的顶部声明一个或多个包名称来创建包。 例如,当您的域名是 _acme.com_ 并且您正在使用名为 _myapp_ 的应用程序中的 _model_ 包中工作时,您的包声明如下所示: +{% tabs packaging-imports-1 %} +{% tab 'Scala 2 and 3' %} ```scala package com.acme.myapp.model class Person ... ``` +{% endtab %} +{% endtabs %} 按照约定,包名应全部小写,正式命名约定为 *\.\.\.\*。 @@ -50,6 +54,22 @@ class Person ... 或者,可以编写仅适用于定义的包子句 他们包含: +{% tabs packaging-imports-1 class=tabs-scala-version %} +{% tab 'Scala 2' %}```scala +package users { + + package administrators { // the full name of this package is users.administrators + class AdminUser // the full name of this class users.administrators.AdminUser + } + package normalusers { // the full name of this package is users.normalusers + class NormalUser // the full name of this class is users.normalusers.NormalUser + } +} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-1 %} + ```scala package users: @@ -59,6 +79,8 @@ package users: package normalusers: // the full name of this package is users.normalusers class NormalUser // the full name of this class is users.normalusers.NormalUser ``` +{% endtab %} +{% endtabs %} 请注意,包名称后跟一个冒号,并且其中的定义 一个包是缩进的。 @@ -76,12 +98,27 @@ package users: 如果您习惯于 Java 之类的语言,则第一类 import 语句与 Java 使用的类似,只是语法略有不同,因此具有更大的灵活性。 这些示例展示了其中的一些灵活性: -```` +{% tabs packaging-imports-2 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import users._ // import everything from the `users` package +import users.User // import only the `User` class +import users.{User, UserPreferences} // import only two selected members +import users.{UserPreferences as UPrefs} // rename a member as you import it +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-2 %} + +```scala import users.* // import everything from the `users` package import users.User // import only the `User` class import users.{User, UserPreferences} // import only two selected members import users.{UserPreferences as UPrefs} // rename a member as you import it -```` +``` + +{% endtab %} +{% endtabs %} 这些示例旨在让您了解第一类 `import` 语句的工作原理。 在接下来的小节中对它们进行了更多解释。 @@ -97,47 +134,93 @@ import users.{UserPreferences as UPrefs} // rename a member as you import it 在 Scala 中,您可以从包中导入一个成员,如下所示: +{% tabs packaging-imports-3 %} +{% tab 'Scala 2 and 3' %} ```scala import scala.concurrent.Future ``` +{% endtab %} +{% endtabs %} 和这样的多个成员: +{% tabs packaging-imports-4 %} +{% tab 'Scala 2 and 3' %} ```scala import scala.concurrent.Future import scala.concurrent.Promise import scala.concurrent.blocking ``` +{% endtab %} +{% endtabs %} 导入多个成员时,您可以像这样更简洁地导入它们: +{% tabs packaging-imports-5 %} +{% tab 'Scala 2 and 3' %} ```scala import scala.concurrent.{Future, Promise, blocking} ``` +{% endtab %} +{% endtabs %} 当您想从 *scala.concurrent* 包中导入所有内容时,请使用以下语法: +{% tabs packaging-imports-6 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import scala.concurrent._ +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-6 %} + ```scala import scala.concurrent.* ``` +{% endtab %} +{% endtabs %} ### 在导入时重命名成员 有时,在导入实体时重命名实体会有所帮助,以避免名称冲突。 例如,如果您想同时使用 Scala `List` 类和 *java.util.List* 类,可以在导入时重命名 *java.util.List* 类: +{% tabs packaging-imports-7 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{List => JavaList} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-7 %} + ```scala import java.util.{List as JavaList} ``` +{% endtab %} +{% endtabs %} 现在您使用名称 `JavaList` 来引用该类,并使用 `List` 来引用 Scala 列表类。 您还可以使用以下语法一次重命名多个成员: +{% tabs packaging-imports-8 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{Date => JDate, HashMap => JHashMap, _} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-8 %} + ```scala import java.util.{Date as JDate, HashMap as JHashMap, *} ``` +{% endtab %} +{% endtabs %} + 那行代码说,“重命名 `Date` 和 `HashMap` 类,如图所示,并导入 _java.util_ 包中的所有其他内容,而不重命名任何其他成员。” ### 在导入时隐藏成员 @@ -145,34 +228,66 @@ import java.util.{Date as JDate, HashMap as JHashMap, *} 您还可以在导入过程中*隐藏*成员。 这个 `import` 语句隐藏了 *java.util.Random* 类,同时导入 *java.util 中的所有其他内容* 包裹: +{% tabs packaging-imports-9 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.util.{Random => _, _} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-9 %} + ```scala import java.util.{Random as _, *} ``` +{% endtab %} +{% endtabs %} 如果您尝试访问 `Random` 类,它将无法正常工作,但您可以访问该包中的所有其他成员: +{% tabs packaging-imports-10 %} +{% tab 'Scala 2 and 3' %} ```scala val r = new Random // won’t compile new ArrayList // works ``` +{% endtab %} +{% endtabs %} #### 隐藏多个成员 要在导入过程中隐藏多个成员,请在使用最终通配符导入之前列出它们: +{% tabs packaging-imports-11 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +scala> import java.util.{List => _, Map => _, Set => _, _} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-11 %} + ```scala scala> import java.util.{List as _, Map as _, Set as _, *} ``` +{% endtab %} +{% endtabs %} 这些类再次被隐藏,但您可以使用 *java.util* 中的所有其他类: +{% tabs packaging-imports-12 %} +{% tab 'Scala 2 and 3' %} ```scala scala> new ArrayList[String] val res0: java.util.ArrayList[String] = [] ``` +{% endtab %} +{% endtabs %} 因为这些 Java 类是隐藏的,所以您也可以使用 Scala 的 `List`、`Set` 和 `Map` 类而不会发生命名冲突: +{% tabs packaging-imports-13 %} +{% tab 'Scala 2 and 3' %} ```scala scala> val a = List(1, 2, 3) val a: List[Int] = List(1, 2, 3) @@ -183,12 +298,32 @@ val b: Set[Int] = Set(1, 2, 3) scala> val c = Map(1 -> 1, 2 -> 2) val c: Map[Int, Int] = Map(1 -> 1, 2 -> 2) ``` +{% endtab %} +{% endtabs %} ### 在任何地方使用导入 在 Scala 中,`import` 语句可以在任何地方。 它们可以在源代码文件的顶部使用: +{% tabs packaging-imports-14 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +package foo + +import scala.util.Random + +class ClassA { + def printRandom(): Unit = { + val r = new Random // use the imported class + // more code here... + } +} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-14 %} + ```scala package foo @@ -199,9 +334,33 @@ class ClassA: val r = new Random // use the imported class // more code here... ``` +{% endtab %} +{% endtabs %} 如果您愿意,您还可以使用更接近需要它们的点的 `import` 语句: +{% tabs packaging-imports-15 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +package foo + +class ClassA { + import scala.util.Random // inside ClassA + def printRandom(): Unit = { + val r = new Random + // more code here... + } +} + +class ClassB { + // the Random class is not visible here + val r = new Random // this code will not compile +} +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-15 %} + ```scala package foo @@ -216,24 +375,52 @@ class ClassB: val r = new Random // this code will not compile ``` +{% endtab %} +{% endtabs %} + ### “静态”导入 当您想以类似于 Java “静态导入”方法的方式导入成员时——因此您可以直接引用成员名称,而不必在它们前面加上类名——使用以下方法。 使用此语法导入 Java `Math` 类的所有静态成员: +{% tabs packaging-imports-16 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.lang.Math._ +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-16 %} + ```scala import java.lang.Math.* ``` +{% endtab %} +{% endtabs %} 现在您可以访问静态的 `Math` 类方法,例如 `sin` 和 `cos`,而不必在它们前面加上类名: +{% tabs packaging-imports-17 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +import java.lang.Math._ + +val a = sin(0) // 0.0 +val b = cos(PI) // -1.0 +``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-17 %} + ```scala import java.lang.Math.* val a = sin(0) // 0.0 val b = cos(PI) // -1.0 ``` +{% endtab %} +{% endtabs %} ### 默认导入的包 @@ -250,17 +437,32 @@ Scala 对象 `Predef` 的成员也是默认导入的。 在极少数情况下会出现命名冲突,您需要从项目的根目录导入一些东西,在包名前加上 `_root_`: +{% tabs packaging-imports-18 class=tabs-scala-version %} +{% tab 'Scala 2' %} +```scala +package accounts + +import _root_.accounts._ ``` + +{% endtab %} +{% tab 'Scala 3' for=packaging-imports-18 %} + +```scala package accounts import _root_.accounts.* ``` +{% endtab %} +{% endtabs %} ## 导入 `given` 实例 正如您将在 [上下文抽象][contextual] 一章中看到的,`import` 语句的一种特殊形式用于导入 `given` 实例。 基本形式如本例所示: +{% tabs packaging-imports-19 %} +{% tab 'Scala 3 only' %} ```scala object A: class TC @@ -271,15 +473,21 @@ object B: import A.* // import all non-given members import A.given // import the given instance ``` +{% endtab %} +{% endtabs %} 在此代码中,对象 `B` 的 `import A.*` 子句导入了 `A` 的所有成员 *除了* `given` 实例 `tc`。 相反,第二个导入,`import A.given`,*仅*导入那个 `given` 实例。 两个 `import` 子句也可以合并为一个: +{% tabs packaging-imports-20 %} +{% tab 'Scala 3 only' %} ```scala object B: import A.{given, *} ``` +{% endtab %} +{% endtabs %} ### 讨论 @@ -297,20 +505,30 @@ object B: 由于给定可以是匿名的,因此按名称导入它们并不总是可行的,通常使用通配符导入。 *按类型导入* 为通配符导入提供了更具体的替代方案,这使得导入的内容更加清晰: +{% tabs packaging-imports-21 %} +{% tab 'Scala 3 only' %} ```scala import A.{given TC} ``` +{% endtab %} +{% endtabs %} 这会在 `A` 中导入任何具有符合 `TC` 的类型的 `given`。 导入多种类型的给定 `T1,...,Tn` 由多个 `given` 选择器表示: +{% tabs packaging-imports-22 %} +{% tab 'Scala 3 only' %} ```scala import A.{given T1, ..., given Tn} ``` +{% endtab %} +{% endtabs %} 导入参数化类型的所有 `given` 实例由通配符参数表示。 例如,当你有这个 `object` 时: +{% tabs packaging-imports-23 %} +{% tab 'Scala 3 only' %} ```scala object Instances: given intOrd as Ordering[Int] @@ -318,25 +536,38 @@ object Instances: given ec as ExecutionContext = ... given im as Monoid[Int] ``` +{% endtab %} +{% endtabs %} 此导入语句导入 `intOrd`、`listOrd` 和 `ec` 实例,但省略了 `im` 实例,因为它不符合任何指定的边界: +{% tabs packaging-imports-24 %} +{% tab 'Scala 3 only' %} ```scala import Instances.{given Ordering[?], given ExecutionContext} ``` +{% endtab %} +{% endtabs %} 按类型导入可以与按名称导入混合。 如果两者都存在于导入子句中,则按类型导入排在最后。 例如,这个 import 子句导入了 `im`、`intOrd` 和 `listOrd`,但省略了 `ec`: +{% tabs packaging-imports-25 %} +{% tab 'Scala 3 only' %} ```scala import Instances.{im, given Ordering[?]} ``` +{% endtab %} +{% endtabs %} ### 一个例子 作为一个具体的例子,假设你有这个 `MonthConversions` 对象,它包含两个 `given` 定义: +{% tabs packaging-imports-26 %} +{% tab 'Scala 3 only' %} + ```scala object MonthConversions: trait MonthConverter[A]: @@ -356,28 +587,45 @@ object MonthConversions: case "feb" => "February" // more cases here ... ``` +{% endtab %} +{% endtabs %} 要将这些给定导入当前范围,请使用以下两个 `import` 语句: +{% tabs packaging-imports-27 %} +{% tab 'Scala 3 only' %} + ```scala import MonthConversions.* import MonthConversions.{given MonthConverter[?]} ``` +{% endtab %} +{% endtabs %} 现在您可以创建一个使用这些 `given` 实例的方法: +{% tabs packaging-imports-28 %} +{% tab 'Scala 3 only' %} + ```scala def genericMonthConverter[A](a: A)(using monthConverter: MonthConverter[A]): String = monthConverter.convert(a) ``` +{% endtab %} +{% endtabs %} 然后您可以在您的应用程序中使用该方法: +{% tabs packaging-imports-29 %} +{% tab 'Scala 3 only' %} + ```scala @main def main = println(genericMonthConverter(1)) // January println(genericMonthConverter("jan")) // January ``` +{% endtab %} +{% endtabs %} 如前所述, `import given` 语法的主要设计优势之一是明确范围内的给定来自何处,并且在这些 `import` 语句中,很清楚地表明给定是来自 `MonthConversions` 对象。