Scala 3 — Book

# 不透明类型

Language

Scala 3 _不透明类型别名_提供没有任何开销的类型抽象。

## 抽象开销

``````class Logarithm(protected val underlying: Double):
def toDouble: Double = math.exp(underlying)
def + (that: Logarithm): Logarithm =
// here we use the apply method on the companion
Logarithm(this.toDouble + that.toDouble)
def * (that: Logarithm): Logarithm =
new Logarithm(this.underlying + that.underlying)

object Logarithm:
def apply(d: Double): Logarithm = new Logarithm(math.log(d))
``````

``````val l2 = Logarithm(2.0)
val l3 = Logarithm(3.0)
println((l2 * l3).toDouble) // prints 6.0
println((l2 + l3).toDouble) // prints 4.999...
``````

## 模块抽象

``````trait Logarithms:

type Logarithm

// operations on Logarithm
def add(x: Logarithm, y: Logarithm): Logarithm
def mul(x: Logarithm, y: Logarithm): Logarithm

// functions to convert between Double and Logarithm
def make(d: Double): Logarithm
def extract(x: Logarithm): Double

// extension methods to use `add` and `mul` as "methods" on Logarithm
extension (x: Logarithm)
def toDouble: Double = extract(x)
def + (y: Logarithm): Logarithm = add(x, y)
def * (y: Logarithm): Logarithm = mul(x, y)
``````

``````object LogarithmsImpl extends Logarithms:

type Logarithm = Double

// operations on Logarithm
def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
def mul(x: Logarithm, y: Logarithm): Logarithm = x + y

// functions to convert between Double and Logarithm
def make(d: Double): Logarithm = math.log(d)
def extract(x: Logarithm): Double = math.exp(x)
``````

`LogarithmsImpl` 的实现中，等式 `Logarithm = Double` 允许我们实现各种方法。

#### 暴露抽象

``````import LogarithmsImpl.*
val l: Logarithm = make(1.0)
val d: Double = l // type checks AND leaks the equality!
``````

``````def someComputation(L: Logarithms)(init: L.Logarithm): L.Logarithm = ...
``````

## 不透明类型

``````object Logarithms:
//vvvvvv this is the important difference!
opaque type Logarithm = Double

object Logarithm:
def apply(d: Double): Logarithm = math.log(d)

extension (x: Logarithm)
def toDouble: Double = math.exp(x)
def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y))
def * (y: Logarithm): Logarithm = x + y
``````

`Logarithm``Double` 相同的事实仅在定义 `Logarithm` 的范围内已知，在上面的示例中对应于对象 `Logarithms`。 类型相等 `Logarithm = Double` 可用于实现方法（如 `*``toDouble`）。

``````import Logarithms.*
val l2 = Logarithm(2.0)
val l3 = Logarithm(3.0)
println((l2 * l3).toDouble) // prints 6.0
println((l2 + l3).toDouble) // prints 4.999...

val d: Double = l2 // ERROR: Found Logarithm required Double
``````