Scala中的隐式转换、类型类与属性测试
立即解锁
发布时间: 2025-08-19 00:05:38 阅读量: 4 订阅数: 12 


Scala 2.13编程实战与进阶
### Scala 中的隐式转换、类型类与属性测试
#### 1. 隐式转换与类型类基础
在 Scala 编程里,有时候需要将 `val` 改为 `def` 以实现参数化。不过,对于不变类型类,广义约束可能会失效,例如:
```scala
scala> implicitly[Cable[UsbConnector] <:< Cable[UsbC[String]]]
^
error: Cannot prove that Cable[UsbConnector] <:< Cable[UsbC[String]].
```
但我们仍能连接线缆:
```scala
scala> connectCable(UsbC("3.1"))
Poly-Connecting UsbC(3.1)
```
此时,编译器能够为类型类选择最具体的实例。若将隐式 `val usbCCable` 的定义重新引入作用域,输出会改变:
```scala
scala> connectCable(UsbC("3.1"))
Connecting USB C 3.1
```
这展示了静态重载解析的工作方式。接下来探讨编译器在需要隐式值时的查找位置与方式。
#### 2. 隐式作用域解析
为了把隐式值置于所需之处,编译器首先要找到它们,这个过程就是隐式作用域解析,它有明确规则,以确保隐式值能如语言规范和开发者预期那样被确定。隐式作用域解析是一个三步过程(若把隐式参数作为方法显式参数提供的情况算上,则是四步,但此情况优先级最高且不涉及隐式查找,故不考虑)。具体步骤如下:
- **当前调用(或词法)作用域**:优先级高于隐式作用域,包含可直接通过名称访问(无需前缀)的隐式值,例如:
- 局部声明
- 外部作用域声明
- 包对象
- 继承链
- 导入语句
- **隐式作用域**:递归查找,包括以下内容:
- 参数的伴生对象
- 超类型的伴生对象
- 混入类型(超特质)的伴生对象
- 类型的伴生对象
- 类型参数的伴生对象
- 类型构造器的伴生对象
- **静态重载规则**:当在某个作用域中找到多个隐式值时使用。
下面通过 mermaid 流程图展示隐式作用域解析的流程:
```mermaid
graph TD;
A[开始] --> B{是否有显式隐式参数};
B -- 是 --> C[使用显式参数];
B -- 否 --> D{词法作用域是否有合适隐式值};
D -- 是 --> E[使用词法作用域隐式值];
D -- 否 --> F{隐式作用域是否有合适隐式值};
F -- 是 --> G{是否有多个隐式值};
G -- 是 --> H[使用静态重载规则选择];
G -- 否 --> I[使用隐式作用域隐式值];
F -- 否 --> J[报错,未找到合适隐式值];
```
#### 3. 词法作用域
词法作用域定义了嵌套语言结构(如方法、函数和其他结构化块)中变量的解析方式。一般来说,外部块的定义在内部块中可见(除非被遮蔽)。以下代码展示了此作用域中隐式解析可能出现的所有冲突:
```scala
package object resolution {
implicit val a: TS = new TS("val in package object") // (1)
}
package resolution {
class TS(override val toString: String)
class Parent {
// implicit val c: TS = new TS("val in parent class") // (2)
}
trait Mixin {
// implicit val d: TS = new TS("val in mixin") // (3)
}
// import Outer._ // (4)
class Outer {
// implicit val e: TS = new TS("val in outer class") // (5)
// import Inner._ // (6)
class Inner(/*implicit (7) */ val arg: TS = implicitly[TS]) extends
Parent with Mixin {
// implicit val f: TS = new TS("val in inner class") (8)
private val resolve = implicitly[TS]
}
object Inner {
implicit val g: TS = new TS("val in companion object")
}
}
object Outer {
implicit val h: TS = new TS("val in parent companion object")
}
}
```
可能的冲突已标注。可以看出,包对象、外部和内部作用域中的隐式值,以及引入到内部或外部作用域的隐式值权重相同。若类构造函数的参数声明为隐式,也会导致冲突。
#### 4. 隐式作用域
隐式作用域优先级低于词法作用域,通常包括(若适用)类型的伴生对象、参数类型的隐式作用域、类型参数的隐式作用域,对于嵌套类型,还包括外部对象。以下示例展示了前三种情况:
```scala
import scala.language.implicitConversions
trait ParentA { def name: String }
trait ParentB
class ChildA(val name: String) extends ParentA with ParentB
object ParentB {
implicit def a2Char(a: ParentA): Char = a.name.head
}
object ParentA {
implicit def a2Int(a: ParentA): Int = a.hashCode()
implicit val ordering = new Ordering[ChildA] {
override def compare(a: ChildA, b: ChildA): Int =
implicitly[Ordering[String]].compare(a.name, b.name)
}
}
object ChildA {
implicit def a2String(a: ParentA): String = a.name
}
trait Test {
def test(a: ChildA) = {
val _: Int = a // companion object of ParentA
val _: String = a // companion object of ChildA
val _: Char = a // companion object of ParentB
}
def constructor[T: Ordering](in: T*): List[T] = in.toList.sorted //
companion object of type constructor
```
0
0
复制全文
相关推荐









