如何理解Scala中的定界缠论笔延续怎么理解

& 2005-, all rights reserved 北京豆网科技有限公司scala 的泛型应用如下:
当构建一个类或者函数时,如果我们不知道(或者说不确定)传入的参数的具体数据类型,这时候可以泛型,例子如下:
object test0 extends App{
val str = &123&
val intv =123
val strTest = new Test[String](str)
val intTest = new Test[Int](intv)
class Test[T](val v:T){
def check = {
if(v.isInstanceOf[String]){
println(&the param is String&);
if(v.isInstanceOf[Int]){
println(&the param is Int&);
the param is String
the param is Int结论:
很多时候我们都需要用到泛型,在web中最常见的就是在用java构建DAO层时,我们往往不知道传入的类型是什么,但是很多时候的操作都是一样的,如增删改查。用泛型+反射的模式可以写一个基于上述操作的通用的模板让所有的需要访问数据库的service层类去调用
二、界定(Bonds)
class Pair[T](val first:T,val second:T){
def smaller = pareTo(second) & 0) first else second //编译器报错,因为编译器不能确定T具有compareTo的方法
object test1 extends App{
val b = &2&
val pair = new Pair(a,b);
print(pair.smaller);
}所以改进如下:
class Pair[T&:Compareable[T]](val first:T,val second:T){
def smaller = pareTo(second) & 0) first else second
修改后就可以运行了。原因是参数的界定是用来限制传入的参数的类型,代表该类型具有这样的一个特性。
object test1 extends App{
val a=3 // 改成整型
val b =2 // 改成整型
val pair = new Pair(a,b); // 这里将会报错,因为整型不是Compareable的子类,不具有compareto方法
print(pair.smaller);
}这时候把Pair的界定改成浏览界定&%,这个界定符可以隐式地转换类型
class Pair[T&%Comparable[T]](val first:T,val second:T){
def smaller = pareTo(second) & 0) first else second
class Pair[T : Ordering](val first: T, val second: T) {
def smaller(implicit ord: Ordering[T]) =
if (pare(first, second) & 0) first else second
}上下文界定符 “:”意味着可以隐式地转换成Ordering[T]
三、类型约束(type contraints)
类型约束也可以给你用来限制类型,方式有三:
These constraints test whether T equals U, is a subtype of U, or is view-convertible to U.
object test3 extends App{
val first = 123
val second =346
val p = new Pair1[Int](first,second) //这里未调用smaller,不报错
p.// 这里会报错,因为first,second被检测到不符合
class Pair1[T](val first: T, val second: T){
// 下面的方法调用了类型约束,当被调用时才会检测约束
def smaller(implicit ev: T &:& Comparable[T]) =
if (pareTo( second) & 0) first else second
四、协变与逆变
这里主要参考文章:/scala-covariance-and-contravariance/&
原文如下:
对于一个带类型参数的类型,比如&List[T],如果对A及其子类型B,满足&List[B]也符合&List[A]的子类型,那么就称为covariance(协变),如果&List[A]是&List[B]的子类型,即与原来的父子关系正相反,则称为contravariance(逆变)
_____________
|_____________|
_____________
|_____________|
_____________
|_____________|
_____________
|_____________|
如果一个类型支持协变或逆变,则称这个类型为variance(翻译为可变的或变型),否则称为invariant(不可变的)
在Java里,泛型类型都是invariant,比如&List&String&&并不是&List&Object&&的子类型。Java并不支持声明点变型(declaration-site
variance,即在定义一个类型时声明它为可变型,也称definition-site),而scala支持,可以在定义类型时声明(用加号表示为协变,减号表示逆变),如:
trait List[+T] // 在类型定义时(declaration-site)声明为协变
这样会把List[String]作为List[Any]的子类型。
不过Java支持使用点变型(use-site variance),所谓“使用点“,也就是在声明变量时:
List&? extends Object& list = new ArrayList&String&();
scala为了兼容java泛型通配符的形式,引入存在类型(existential type,后边再讲)时,也支持了使用点变型(use-site variance)
scala& val a : List[_ &: Any] = List[String](&A&)
a: List[_] = List(A)
要注意variance并不会被继承,父类声明为variance,子类如果想要保持,仍需要声明:
scala& trait A[+T]
scala& class C[T] extends A[T]
// C是invariant的
scala& class X; class Y extends X;
scala& val t:C[X] = new C[Y]
&console&:11: error:
required: C[X]
Note: Y &: X, but class C is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
必须也对C声明为协变的才行:
scala& class C[+T] extends A[T]
scala& val t:C[X] = new C[Y]
t: C[X] = C@6a079142
-----------------------------新增-----------------------------
扩展---实际应用中理解逆变和协变(-)
在scala中内置一个特征函数:
trait&Function1[-S,&+T]&{&&
&&def&apply(x:&S):&T&&
这种函数接受一个参数,参数类型为泛型类型T,返回类型为泛型类型U。和其他支持泛型的语言一样,实际定义函数时T和U的类型会被确定下来,不过需要注意的是,这边的T之前有一个“-”,而U之前有一个“+”。
在这里引入关于这个符号的说明,在声明Scala的泛型类型时,“+”表示协变,而“-”表示逆变。
C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。
根据Liskov替换原则,如果A是B的子类,那么能适用于B的所有操作,都适用于A。让我们看看这边Function1的定义,是否满足这样的条件。假设Bird是Animal的子类,那么看看下面两个函数之间是什么关系:
def f1(x: Bird): Animal // instance of Function1[Bird, Animal]
def f2(x: Animal): Bird // instance of Function1[Animal, Bird]
在这里f2的类型是f1的类型的子类。为什么?
我们先看一下参数类型,根据Liskov替换原则,f1能够接受的参数,f2也能接受。在这里f1接受的Bird类型,f2显然可以接受,因为Bird对象可以被当做其父类Animal的对象来使用。
再看返回类型,f1的返回值可以被当做Animal的实例使用,f2的返回值可以被当做Bird的实例使用,当然也可以被当做Animal的实例使用。
所以我们说,函数的参数类型是逆变的,而函数的返回类型是协变的。
(注意上面的f1,f2均是被当做变量传值时的状态)
如果上面的例子还不能明白,请看下面完整例子:
扩展---实际应用中理解逆变和协变(二)
&span style=&font-family:SimSfont-size:18&&package fineqtbull.customer
//出版物类
class Publication(val title: String)
class Book(title: String) extends Publication(title)
//图书库类
object Library {
//定义图书库内所有的书籍
val books: Set[Book] =
new Book(&Programming in Scala&),
new Book(&Walden&)
//打印所有图书内容,使用外部传入的函数来实现
def printBookList(info: Book =& AnyRef) {
//确认Scala中一个参数的函数实际上是Function1特征的实例
assert(info.isInstanceOf[Function1[_, _]])
for (book &- books)
println(info(book))
//打印所有图书内容,使用外部传入的GetInfoAction特征的实例来实现
def printBokkListByTrait[P &: Book, R &: AnyRef](
action : GetInfoAction[P, R]) {
for (book &- books)
println(action(book))
//取得图书内容特征,P类型参数的类型下界是Book,R类型参数的类型上界是AnyRef
trait GetInfoAction[P &: Book, R &: AnyRef] {
//取得图书内容的文本描述,对应()操作符
def apply(book : P) : R
//单例对象,文件的主程序
object Customer extends Application {
//定义取得出版物标题的函数
def getTitle(p: Publication): String = p.title
//使用函数来打印
Library.printBookList(getTitle)
//使用特征GetInfoAction的实例来打印
Library.printBokkListByTrait(new GetInfoAction[Publication, String] {
def apply(p: Publication) : String = p.title })
printBookList的info参数是Function1类型,而&Function1的-S类型参数是逆变,+T参数是协变。printBookList方法的assert(info.isInstanceOf[Function1[_, _]])语句可以验证这一点。从printBookList方法的定义可以知道,info的S类型参数是Book,T类型参数是AnyRef。然而主函数中使用处则是Library.printBookList(getTitle),getTitle函数中对应的S是Publication,T是String。为什么可以与printBookList原来的定义不一致呢,这就是协变和逆变的威力了。由于-S是逆变,而Publication是Book的父类,所以Publication可以代替(泛化为)Book。由于+T是协变,而String是AnyRef的子类,所以String可以代替(泛化为)AnyRef。如此一来,主程序的语句也就完全正确了。
为什么要遵循Function1这类的特性呢?你想想getTitle是真正实现函数体的变量,所以getTitle接受的参数p必须是printBookList参数中的info的父类。很多学java的程序猿分不清楚逆变的作用,就是没有搞懂在scala中函数可以作为参数传入方法以及哪个def才是实现内容主体的函数并被作为实参。
本文已收录于以下专栏:
相关文章推荐
不得不说这一章题量有点狠,接着干吧
用foldLeft实现sum,product,length
def sum3(ns: List[Int]) = foldLeft(ns, 1)(_...
下面的例子展示了如何加载数据,解析为RDD(译者注:RDD为Spark的弹性数据集);然后利用线形回归+随机梯度下降算法构建一个线形模型,并进行预测,最后计算均方误差来对模型进行评估。
程序员升职加薪指南!还缺一个“证”!
CSDN出品,立即查看!
开始本博客之前,请先阅读:
Retrofit请求数据对错误以及网络异常的处理
实际开发经常有这种情况,比如登录请求,接口返回的
信息包括请求返回的状态:失败还是成功...
下面的Scala代码展示了如何使用支持向量机(SVM)算法进行二类分类,包括以下基本步骤:
1、加载训练集到Spark空间
2、执行支持向量机(SVM)算法对该数据集进行训练,获得一个模型
1.apply方法当scala中类或者对象有一个主要用途的时候,apply方法就是一个很好地语法糖。请看下面一个简单的例子:class Foo(foo: String) {
}object Foo {...
/articles/NBzAzy江湖传闻,scala开发的最佳利器乃 JetBrains 的神作 IntelliJ IDEA ,外加构建工具sbt 是也。但...
看scala有2周了,一直都是SPEL的方式运行。最近打算把手头这台古董本本换个ubutnu,作scala练习环境。
废话不多说,进入正题
安装JDK,oracle观望下载JDK7D的tar包,用...
转自:http://my.oschina.net/scipio/blog/282794
协变和逆变是描述在集合中的多态关系与原来类型多态关系之间的关系。如果T1是T的子类,那么Container[T1]是不是Container[T]的子类呢?Variance...
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)scala 泛型之初解,定界,类型约束,逆变与协变
scala 的泛型应用如下:
当构建一个类或者函数时,如果我们不知道(或者说不确定)传入的参数的具体数据类型,这时候可以泛型,例子如下:
object test0 extends App{
val str = &123&
val intv =123
val strTest = new Test[String](str)
val intTest = new Test[Int](intv)
class Test[T](val v:T){
def check = {
if(v.isInstanceOf[String]){
println(&the param is String&);
if(v.isInstanceOf[Int]){
println(&the param is Int&);
the param is String
the param is Int结论:
很多时候我们都需要用到泛型,在web中最常见的就是在用java构建DAO层时,我们往往不知道传入的类型是什么,但是很多时候的操作都是一样的,如增删改查。用泛型+反射的模式可以写一个基于上述操作的通用的模板让所有的需要访问数据库的service层类去调用
二、界定(Bonds)
class Pair[T](val first:T,val second:T){
def smaller = pareTo(second) & 0) first else second //编译器报错,因为编译器不能确定T具有compareTo的方法
object test1 extends App{
val b = &2&
val pair = new Pair(a,b);
print(pair.smaller);
}所以改进如下:
class Pair[T&:Compareable[T]](val first:T,val second:T){
def smaller = pareTo(second) & 0) first else second
修改后就可以运行了。原因是参数的界定是用来限制传入的参数的类型,代表该类型具有这样的一个特性。
object test1 extends App{
val a=3 // 改成整型
val b =2 // 改成整型
val pair = new Pair(a,b); // 这里将会报错,因为整型不是Compareable的子类,不具有compareto方法
print(pair.smaller);
}这时候把Pair的界定改成浏览界定&%,这个界定符可以隐式地转换类型
class Pair[T&%Comparable[T]](val first:T,val second:T){
def smaller = pareTo(second) & 0) first else second
class Pair[T : Ordering](val first: T, val second: T) {
def smaller(implicit ord: Ordering[T]) =
if (pare(first, second) & 0) first else second
}上下文界定符 “:”意味着可以隐式地转换成Ordering[T]
三、类型约束(type contraints)
类型约束也可以给你用来限制类型,方式有三:
These constraints test whether T equals U, is a subtype of U, or is view-convertible to U.
object test3 extends App{
val first = 123
val second =346
val p = new Pair1[Int](first,second) //这里未调用smaller,不报错
p.// 这里会报错,因为first,second被检测到不符合
class Pair1[T](val first: T, val second: T){
// 下面的方法调用了类型约束,当被调用时才会检测约束
def smaller(implicit ev: T &:& Comparable[T]) =
if (pareTo( second) & 0) first else second
四、协变与逆变
这里主要参考文章:/scala-covariance-and-contravariance/&
原文如下:
对于一个带类型参数的类型,比如&List[T],如果对A及其子类型B,满足&List[B]也符合&List[A]的子类型,那么就称为covariance(协变),如果&List[A]是&List[B]的子类型,即与原来的父子关系正相反,则称为contravariance(逆变)
_____________
|_____________|
_____________
|_____________|
_____________
|_____________|
_____________
|_____________|
如果一个类型支持协变或逆变,则称这个类型为variance(翻译为可变的或变型),否则称为invariant(不可变的)
在Java里,泛型类型都是invariant,比如&List&String&&并不是&List&Object&&的子类型。Java并不支持声明点变型(declaration-site
variance,即在定义一个类型时声明它为可变型,也称definition-site),而scala支持,可以在定义类型时声明(用加号表示为协变,减号表示逆变),如:
trait List[+T] // 在类型定义时(declaration-site)声明为协变
这样会把List[String]作为List[Any]的子类型。
不过Java支持使用点变型(use-site variance),所谓“使用点“,也就是在声明变量时:
List&? extends Object& list = new ArrayList&String&();
scala为了兼容java泛型通配符的形式,引入存在类型(existential type,后边再讲)时,也支持了使用点变型(use-site variance)
scala& val a : List[_ &: Any] = List[String](&A&)
a: List[_] = List(A)
要注意variance并不会被继承,父类声明为variance,子类如果想要保持,仍需要声明:
scala& trait A[+T]
scala& class C[T] extends A[T]
// C是invariant的
scala& class X; class Y extends X;
scala& val t:C[X] = new C[Y]
&console&:11: error:
required: C[X]
Note: Y &: X, but class C is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
必须也对C声明为协变的才行:
scala& class C[+T] extends A[T]
scala& val t:C[X] = new C[Y]
t: C[X] = C@6a079142
-----------------------------新增-----------------------------
扩展---实际应用中理解逆变和协变(-)
在scala中内置一个特征函数:
trait&Function1[-S,&+T]&{&&
&&def&apply(x:&S):&T&&
这种函数接受一个参数,参数类型为泛型类型T,返回类型为泛型类型U。和其他支持泛型的语言一样,实际定义函数时T和U的类型会被确定下来,不过需要注意的是,这边的T之前有一个“-”,而U之前有一个“+”。
在这里引入关于这个符号的说明,在声明Scala的泛型类型时,“+”表示协变,而“-”表示逆变。
C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。
根据Liskov替换原则,如果A是B的子类,那么能适用于B的所有操作,都适用于A。让我们看看这边Function1的定义,是否满足这样的条件。假设Bird是Animal的子类,那么看看下面两个函数之间是什么关系:
def f1(x: Bird): Animal // instance of Function1[Bird, Animal]
def f2(x: Animal): Bird // instance of Function1[Animal, Bird]
在这里f2的类型是f1的类型的子类。为什么?
我们先看一下参数类型,根据Liskov替换原则,f1能够接受的参数,f2也能接受。在这里f1接受的Bird类型,f2显然可以接受,因为Bird对象可以被当做其父类Animal的对象来使用。
再看返回类型,f1的返回值可以被当做Animal的实例使用,f2的返回值可以被当做Bird的实例使用,当然也可以被当做Animal的实例使用。
所以我们说,函数的参数类型是逆变的,而函数的返回类型是协变的。
(注意上面的f1,f2均是被当做变量传值时的状态)
如果上面的例子还不能明白,请看下面完整例子:
扩展---实际应用中理解逆变和协变(二)
&span style=&font-family:SimSfont-size:18&&package fineqtbull.customer
//出版物类
class Publication(val title: String)
class Book(title: String) extends Publication(title)
//图书库类
object Library {
//定义图书库内所有的书籍
val books: Set[Book] =
new Book(&Programming in Scala&),
new Book(&Walden&)
//打印所有图书内容,使用外部传入的函数来实现
def printBookList(info: Book =& AnyRef) {
//确认Scala中一个参数的函数实际上是Function1特征的实例
assert(info.isInstanceOf[Function1[_, _]])
for (book &- books)
println(info(book))
//打印所有图书内容,使用外部传入的GetInfoAction特征的实例来实现
def printBokkListByTrait[P &: Book, R &: AnyRef](
action : GetInfoAction[P, R]) {
for (book &- books)
println(action(book))
//取得图书内容特征,P类型参数的类型下界是Book,R类型参数的类型上界是AnyRef
trait GetInfoAction[P &: Book, R &: AnyRef] {
//取得图书内容的文本描述,对应()操作符
def apply(book : P) : R
//单例对象,文件的主程序
object Customer extends Application {
//定义取得出版物标题的函数
def getTitle(p: Publication): String = p.title
//使用函数来打印
Library.printBookList(getTitle)
//使用特征GetInfoAction的实例来打印
Library.printBokkListByTrait(new GetInfoAction[Publication, String] {
def apply(p: Publication) : String = p.title })
printBookList的info参数是Function1类型,而&Function1的-S类型参数是逆变,+T参数是协变。printBookList方法的assert(info.isInstanceOf[Function1[_, _]])语句可以验证这一点。从printBookList方法的定义可以知道,info的S类型参数是Book,T类型参数是AnyRef。然而主函数中使用处则是Library.printBookList(getTitle),getTitle函数中对应的S是Publication,T是String。为什么可以与printBookList原来的定义不一致呢,这就是协变和逆变的威力了。由于-S是逆变,而Publication是Book的父类,所以Publication可以代替(泛化为)Book。由于+T是协变,而String是AnyRef的子类,所以String可以代替(泛化为)AnyRef。如此一来,主程序的语句也就完全正确了。
为什么要遵循Function1这类的特性呢?你想想getTitle是真正实现函数体的变量,所以getTitle接受的参数p必须是printBookList参数中的info的父类。很多学java的程序猿分不清楚逆变的作用,就是没有搞懂在scala中函数可以作为参数传入方法以及哪个def才是实现内容主体的函数并被作为实参。
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?Scala中的协变,逆变,上界,下界等 - 推酷
Scala中的协变,逆变,上界,下界等
Scala中的协变逆变和Java中的协变逆变不一样,看起来更复杂。 本文对Scala中的这些概念做一总结。首先看几个概念:
协变。使你能够使用比原始指定的类型的子类
Contravariance
逆变。使你能够使用比原始指定的类型的父类。
Invariance
不变。你只能使用原始指定的类型,不能协变和逆变
Upper bounds
Lower bounds
Java中的协变和逆变
首先我们先回顾一下Java中的协变和逆变,这样我们更容易理解Scala中的协变和逆变。
class Super {
Object getSomething(){}
class Sub extends Super {
String getSomething() {}
Sub.getSomething()是一个协变类型,因为它的返回类型是Super.getSomething返回类型的子类。
class Super{
voiddoSomething(String parameter)
class Sub extends Super{
voiddoSomething(Object parameter)
Sub.getSomething()是一个逆变类型,因为它的输入参数是Super.getSomething输入参数的父类。
泛型中也有协变和逆变。
List&String& aList...
List&? extends Object& covariantList = aL
List&? superString& contravariantList = aL
covariantList.add(&d&);//wrong
Object a = covariantList.get(0);
contravariantList.add(&d&);//OK
String b = contravariantList.get(1);//wrong
Object c = contravariantList.get(2);
你可以调用
covariantList
所有的不需要泛型参数的方法,因为泛型参数必须
extends Object
, 但是编译时你不知道它确切的类型。但是你可以调用getter方法,因为返回类型总是符合Object类型。
contravariantList
正好相反,你可以调用所有的带泛型参数的方法,因为你明确的可以传入一个String的父类。但是getter方法却不行。
Scala的协变
首先我们需要了解的是子类型(subtyping)。一个类可以是其它类的子类(sub-)或者父类(super-)。我们可以使用数学概念(
A -&BiffA&:B
当我们定义一个协变类型
时,List[Child]可以是List[Parent]的子类型。
当我们定义一个逆变类型
时,List[Child]可以是List[Parent]的父类型。
看下面的例子:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[T](t: T){
classTestextendsApp{
valc:Consumer[Bird] =newConsumer[Bird](newBird)
valc2:Consumer[Animal] = c
不能赋值给
定义成不变类型。
稍微改一下:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[+T](t: T){
classTestextendsApp{
valc:Consumer[Bird] =newConsumer[Bird](newBird)
valc2:Consumer[Animal] = c
定义成协变类型的,所以
Consumer[Bird]
Consumer[Animal]
的子类型,所以它可以被赋值给
Scala的逆变
将上面的例子改一下:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[-T](t: T){
classTestextendsApp{
valc:Consumer[Bird] =newConsumer[Bird](newBird)
valc2:Consumer[Hummingbird] = c
Consumer[-T]
定义成逆变类型,所以
Consumer[Bird]
Consumer[Hummingbird]
的子类型,故
可以被赋值给
下界lower bounds
如果协变类包含带类型参数的方法时:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[+T](t: T){
defuse(t: T) = {}
编译会出错。出错信息为 &Covariant type T occurs in contravariant position in type T of value t&。但是如果返回结果为类型参数则没有问题。
classAnimal{}
classBirdextendsAnimal{}
classConsumer[+T](t: T){
defget(): T = {newT}
为了在方法的参数中使用类型参数,你需要定义下界:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[+T](t: T){
defuse[U &: T](u : U) = {println(u)}
上界upper bounds
看一下逆变类中使用上界的例子:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[-T](t: T){
defget[U &: T](): U = {newU}
看以看到方法的返回值是协变的位置,方法的参数是逆变的位置。
因此协变类的类型参数可以用在方法的返回值的类型,在方法的参数类型上必须使用下界绑定
逆变类的类型参数可以用在方法的参数类型上,用做方法的返回值类型时必须使用上界绑定
综合协变,逆变,上界,下界
一个综合例子:
classAnimal{}
classBirdextendsAnimal{}
classConsumer[-S,+T](){
defm1[U &: T](u: U): T = {newT}//协变,下界
defm2[U &: S](s: S): U = {newU}//逆变,上界
classTestextendsApp{
valc:Consumer[Animal,Bird] =newConsumer[Animal,Bird]()
valc2:Consumer[Bird,Animal] = c
c2.m1(newAnimal)
c2.m2(newBird)
View Bound
Scala还有一种视图绑定的功能,如
classBird{defsing = {}}
classToy{}
classConsumer[T&%Bird](){
defuse(t: T) = t.sing
或者类型参数在方法上:
classBird{defsing = {}}
classToy{}
classConsumer(){
defuse[T &% Bird](t: T) = t.sing
classTestextendsApp{
valc =newConsumer()
c.use(newToy)
它要求T必须有一种隐式转换能转换成Bird,也就是
,否则上面的代码会编译出错:
No implicitview availablefromToy =& Bird.
加入一个隐式转换,编译通过。
importscala.language.implicitConversions
classBird{defsing = {}}
classToy{}
classConsumer(){
defuse[T &% Bird](t: T) = t.sing
classTestextendsApp{
implicit deftoy2Bird(t: Toy) =newBird
valc =newConsumer()
c.use(newToy)
Context Bound
context bound在Scala 2.8.0中引入,也被称作
type class pattern
view bound使用
A &% String
方式,context bound则需要参数化的类型,如
Ordered[A]
它声明了一个类型
,隐式地有一个类型
,语法如下:
deff[A : B](a: A) = g(a)// where g requires an implicit value of type B[A]
更清晰的一个例子:
deff[A : ClassManifest](n: Int) =newArray[A](n)
deff[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 初中延续性动词 的文章

 

随机推荐