第 6 章 抽象化上下文:使用分句
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
在第 5 章中,我们开始讨论 Scala 2 和 3 中用于对上下文进行抽象的强大工具和习语。特别是,我们讨论了类型类、扩展方法和隐式转换,它们是扩展现有类型行为的工具。
本章将探讨使用子句,这些子句与给定实例配合使用,以解决特定的设计方案并简化用户代码。
使用分句
上下文抽象的另一个主要用途是隐式而非显式地提供方法参数。当方法参数列表以关键字using (Scala 3)或implicit (Scala 2 和 3)开头时,只要给定的实例或隐式值在编译器可以使用的范围内,用户就不必显式地提供参数值。
在 Scala 2 术语中,这些方法参数被称为隐式参数,整个参数列表就是隐式参数列表或隐式参数子句。只允许有一个这样的列表,其中包含所有隐式参数。在 Scala 3 中,它们是上下文参数,整个参数列表是一个 using 子句。使用子句可以不止一个。1下面是一个示例:
classBankAccount(...):defdebit(amount:Money)(usingtransaction:Transaction)...
在这里,using 子句以using 关键字开头,包含上下文参数transaction 。
在 Scala 2 中,可用于填写这些参数的作用域中的值被称为隐含值。在 Scala 3 中,它们是给定实例,简称givens。
在本书中,我将主要使用 Scala 3 术语,但当我使用 Scala 2 术语时,通常是在讨论使用implicit 定义和参数的 Scala 2 库时。Scala 3 或多或少会将它们互换对待,不过 Scala 2 的 implicits 最终会被逐步淘汰。
对于 using 子句中的每个参数,外层作用域中必须存在类型兼容的给定值。使用 Scala 2 风格的隐式,隐式值或返回兼容值的隐式方法或类必须在作用域中。
为了便于比较,请回顾一下您还可以为方法参数定义默认值。虽然在很多情况下都足够了,但它们在编译时静态地作用于方法定义,并由方法的实现者定义。另一方面,使用条款为方法的使用者提供了更大的灵活性。
举个例子,假设我们实现了一种简单的类型,它可以封装序列以方便排序(忽略Seq 已经提供了这种功能这一事实)。一种方法是由用户提供一个 math.Ordering的实现,它知道如何对序列中使用的特定类型的元素进行排序。该对象可以作为参数传递给sort 方法,但用户可能也希望能一次性指定给定值,然后让相同元素类型的所有序列都自动使用该值。
第一个实现使用的语法对 Scala 2 和 Scala 3 都有效:
// src/script/scala-2/progscala3/contexts/ImplicitClauses.scalacaseclassSortableSeq[A](seq:Seq[A]){defsortBy1[B](transform:A=>B)(implicito:Ordering[B]):SortableSeq[A]=SortableSeq(seq.sortBy(transform)(o))defsortBy2 ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access