有时候,你并不需要指定一个类型是等/子/超于另一个类,你可以通过转换这个类来伪装这种关联关系。一个视界指定一个类型可以被“看作是”另一个类型。这对对象的只读操作是很有用的。
隐函数允许类型自动转换。更确切地说,在隐式函数可以帮助满足类型推断时,它们允许按需的函数应用。例如:
scala> implicit def strToInt(x: String) = x.toInt
strToInt: (x: String)Int
scala> "123"
res0: java.lang.String = 123
scala> val y: Int = "123"
y: Int = 123
scala> math.max("123", 111)
res1: Int = 123
//视界,就像类型边界,要求对给定的类型存在这样一个函数。您可以使用<%指定类型限制,例如:
scala> class Container[A <% Int] { def addIt(x: A) = 123 + x }
defined class Container
//这是说 A 必须“可被视”为 Int 。让我们试试。
scala> (new Container[String]).addIt("123")
res11: Int = 246
scala> (new Container[Int]).addIt(123)
res12: Int = 246
scala> (new Container[Float]).addIt(123.2F)
<console>:8: error: could not find implicit value for evidence parameter of type (Float) => Int
(new Container[Float]).addIt(123.2)
^
方法可以通过隐含参数执行更复杂的类型限制。例如,List 支持对数字内容执行 sum,但对其他内容却不行。可是 Scala 的数字类型并不都共享一个超类,所以我们不能使用T <: Number。相反,要使之能工作,Scala 的 math 库对适当的类型 T 定义了一个隐含的 Numeric[T]。 然后在 List 定义中使用它:
sum[B >: A](implicit num: Numeric[B]): B
如果你调用List(1,2).sum(),你并不需要传入一个 num 参数;它是隐式设置的。但如果你调用 List(“whoop”).sum(),它会抱怨无法设置 num。
在没有设定陌生的对象为 Numeric 的时候,方法可能会要求某种特定类型的“证据”。这时可以使用以下类型-关系运算符:
A =:= B A 必须和 B 相等 A <:< B A 必须是 B 的子类 A <%< B A 必须可以被看做是 B
scala> class Container[A](value: A) { def addIt(implicit evidence: A =:= Int) = 123 + value }
defined class Container
scala> (new Container(123)).addIt
res11: Int = 246
scala> (new Container("123")).addIt
<console>:10: error: could not find implicit value for parameter evidence: =:=[java.lang.String,Int]
//类似地,根据之前的隐式转换,我们可以放松约束为可视性:
scala> class Container[A](value: A) { def addIt(implicit evidence: A <%< Int) = 123 + value }
defined class Container
scala> (new Container("123")).addIt
res15: Int = 246
Scala 支持结构类型 structural types — 类型需求由接口构造表示,而不是由具体的类型表示。
scala> def foo(x: { def get: Int }) = 123 + x.get
foo: (x: AnyRef{def get: Int})Int
scala> foo(new { def get = 10 })
res0: Int = 133
在特质中,你可以让类型成员保持抽象。
scala> trait Foo { type A; val x: A; def getX: A = x }
defined trait Foo
scala> (new Foo { type A = Int; val x = 123 }).getX
res3: Int = 123
scala> (new Foo { type A = String; val x = "hey" }).getX
res4: java.lang.String = hey
学习: https://www.w3cschool.cn/scala/3gpw1jci.html