强制所有某种类型“T”对特征“F”的方法的输入先前已由“F”本身生成
Enforce that all inputs of some type `T` to methods of a trait `F` have been previously produced by `F` itself
假设我有一些特质Foo
,例如:
trait Foo {
def bar: List[Int]
def baz(i: Int): Unit
}
我想在编译时强制传递给 baz
的所有输入都已由 bar
生成。例如,如果这是 Foo
:
的实现
object A extends Foo {
def bar = List(2, 3, 5, 7)
def baz(i: Int): Unit = {
if (bar contains i) println("ok")
else println("not good")
}
}
然后我想强制只能将个位数的质数传递给 baz
。如果已知 baz
的输入类型是 Int
,这显然不起作用,因为它允许我实例化各种非质数且不在 0
和 [ 之间的整数=22=]:
val okValues: List[Int] = A.bar
A.baz(okValues(1)) // ok
A.baz(3) // ok (but dangerous! `3` appeared out of nowhere!)
A.baz(42) // not good
如何强制只有 bar
之前生成的值才能传递给 baz
?
什么不起作用
将 Int
转换为 Foo
的类型成员没有帮助,因为它在 [=14] 的实现 A
中被实例化为具体类型 Int
=]:
trait Foo {
type T
def bar: List[T]
def baz(t: T): Unit
}
object A extends Foo {
type T = Int
def bar = List(2, 3, 4, 5)
def baz(i: Int): Unit = {
if (bar contains i) println("ok")
else println("not good")
}
}
A.baz(42) // not good
这是一个解决方案,它依赖于用抽象类型成员 T
替换具体类型 Int
,然后根本不公开 T
的具体实现 [=11] =]:
- 将具体类型
Int
替换为抽象类型成员 T
- 将方法
bar
和 baz
以及类型 T
移动到内部特征 YFoo
- 在
Foo
中,提供一个生成 YFoo
但不暴露 T
是什么的方法。
在代码中:
trait Foo {
trait YFoo {
type T
def bar: List[T]
def baz(i: T): Unit
}
def yFoo: YFoo
}
object B extends Foo {
def yFoo: YFoo = new YFoo {
type T = Int
def bar: List[Int] = List(2, 3, 5, 7)
def baz(i: Int): Unit = {
if (bar contains i) println("ok")
else println("not good")
}
}
}
val a = B.yFoo
val okValues: List[a.T] = a.bar
a.baz(okValues(1)) // ok
// a.baz(3) // dangerous stuff doesn't compile!
// found : Int(3)
// required: a.T
// a.baz(42) // invalid stuff also doesn't compile
// found : Int(42)
// required: a.T
现在所有危险/无效的东西甚至都无法编译。您可以传递给 baz
的唯一值是由 bar
.
生成的 "list of certified values" 中的值
假设我有一些特质Foo
,例如:
trait Foo {
def bar: List[Int]
def baz(i: Int): Unit
}
我想在编译时强制传递给 baz
的所有输入都已由 bar
生成。例如,如果这是 Foo
:
object A extends Foo {
def bar = List(2, 3, 5, 7)
def baz(i: Int): Unit = {
if (bar contains i) println("ok")
else println("not good")
}
}
然后我想强制只能将个位数的质数传递给 baz
。如果已知 baz
的输入类型是 Int
,这显然不起作用,因为它允许我实例化各种非质数且不在 0
和 [ 之间的整数=22=]:
val okValues: List[Int] = A.bar
A.baz(okValues(1)) // ok
A.baz(3) // ok (but dangerous! `3` appeared out of nowhere!)
A.baz(42) // not good
如何强制只有 bar
之前生成的值才能传递给 baz
?
什么不起作用
将 Int
转换为 Foo
的类型成员没有帮助,因为它在 [=14] 的实现 A
中被实例化为具体类型 Int
=]:
trait Foo {
type T
def bar: List[T]
def baz(t: T): Unit
}
object A extends Foo {
type T = Int
def bar = List(2, 3, 4, 5)
def baz(i: Int): Unit = {
if (bar contains i) println("ok")
else println("not good")
}
}
A.baz(42) // not good
这是一个解决方案,它依赖于用抽象类型成员 T
替换具体类型 Int
,然后根本不公开 T
的具体实现 [=11] =]:
- 将具体类型
Int
替换为抽象类型成员T
- 将方法
bar
和baz
以及类型T
移动到内部特征YFoo
- 在
Foo
中,提供一个生成YFoo
但不暴露T
是什么的方法。
在代码中:
trait Foo {
trait YFoo {
type T
def bar: List[T]
def baz(i: T): Unit
}
def yFoo: YFoo
}
object B extends Foo {
def yFoo: YFoo = new YFoo {
type T = Int
def bar: List[Int] = List(2, 3, 5, 7)
def baz(i: Int): Unit = {
if (bar contains i) println("ok")
else println("not good")
}
}
}
val a = B.yFoo
val okValues: List[a.T] = a.bar
a.baz(okValues(1)) // ok
// a.baz(3) // dangerous stuff doesn't compile!
// found : Int(3)
// required: a.T
// a.baz(42) // invalid stuff also doesn't compile
// found : Int(42)
// required: a.T
现在所有危险/无效的东西甚至都无法编译。您可以传递给 baz
的唯一值是由 bar
.