匯入給定值
匯入給定實例時,會使用一種特殊的匯入萬用字元選擇器形式。範例
object A:
class TC
given tc: TC = ???
def f(using TC) = ???
object B:
import A.*
import A.given
...
在上面的程式碼中,物件 B
中的 import A.*
子句會匯入 A
的所有成員,除了給定實例 tc
。相反地,第二個匯入 import A.given
將只匯入那個給定實例。這兩個匯入子句也可以合併成一個
object B:
import A.{given, *}
...
一般來說,一般的萬用字元選擇器 *
會將給定或擴充以外的所有定義納入範圍,而 given
選擇器會將所有給定(包括由擴充產生的給定)納入範圍。
這些規則產生兩個主要好處
- 它更清楚地說明範圍內的給定來自何處。特別是,無法在長長的常規萬用字元匯入清單中隱藏已匯入的給定。
- 它可以在不匯入任何其他內容的情況下匯入所有給定。這特別重要,因為給定可以是匿名的,因此使用命名匯入的通常方法並不實用。
按類型匯入
由於給定值可以是匿名的,因此無法總是透過其名稱來導入,而通常會使用萬用字元導入。依類型導入提供比萬用字元導入更明確的替代方案,這使得導入的內容更為清楚。範例
import A.given TC
這會導入 A
中任何符合 TC
類型的給定值。導入多種類型 T1,...,Tn
的給定值會以多個 given
選擇器表示。
import A.{given T1, ..., given Tn}
導入參數化類型的所有給定實例會以萬用字元引數表示。例如,假設物件
object Instances:
given intOrd: Ordering[Int] = ...
given listOrd[T: Ordering]: Ordering[List[T]] = ...
given ec: ExecutionContext = ...
given im: Monoid[Int] = ...
導入子句
import Instances.{given Ordering[?], given ExecutionContext}
會導入 intOrd
、listOrd
和 ec
實例,但會略過 im
實例,因為它不符合任何指定的界線。
依類型導入可以與依名稱導入混合使用。如果兩者都存在於導入子句中,依類型導入會排在最後。例如,導入子句
import Instances.{im, given Ordering[?]}
會導入 im
、intOrd
和 listOrd
,但會略過 ec
。
移轉
上述的導入規則導致函式庫必須與其所有使用者同步從舊式隱含和一般導入移轉到給定值和給定導入。
下列修改可避免此移轉障礙。
-
given
導入選擇器也會將舊式隱含引入範圍。因此,在 Scala 3.0 中,舊式隱含定義可以透過*
或given
萬用字元選擇器引入範圍。 -
在 Scala 3.1 中,透過
*
萬用字元導入存取的舊式隱含會發出不建議使用的警告。 -
在 3.1 之後的某個版本中,透過
*
萬用字元導入存取的舊式隱含會產生編譯器錯誤。
這些規則表示函式庫使用者可以在 Scala 3.0 中使用 given
選擇器存取舊式隱含,並會在後續版本中被溫和地推動,然後被迫這麼做。然後,函式庫可以在使用者基礎移轉後切換到給定實例。
語法
Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
ImportSpec ::= NamedSelector
| WildcardSelector
| ‘{’ ImportSelectors) ‘}’
NamedSelector ::= id [‘as’ (id | ‘_’)]
WildCardSelector ::= ‘*' | ‘given’ [InfixType]
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
| WildCardSelector {‘,’ WildCardSelector}