热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Scala尾递归泛型类型上下限界定多重界定视图界定型变(协变逆变)隐式转换SAM...

0.尾递归可以进行优化,将递归转换成循环实现,避免栈的溢出。defsum(args:Seq[Int]):BigInt{if(args.isEmpty)

0.尾递归

可以进行优化,将递归转换成循环实现,避免栈的溢出。
def sum(args:Seq[Int]):BigInt = {if(args.isEmpty) 0 else args.head + sum(args.tail)
}
sum(1 to 10000) //溢出//实现了尾递归//实现尾递归sum2函数接受两个函数x:Seq[Int]:序列 part:BigInt:累加求和每次产生的部分值
def sum2(x:Seq[Int] , part :BigInt):BigInt = {if(x.isEmpty) part else sum2( x.tail ,x.head + part)
}
sum2(1 to 100000 , 0) //okdef out(str:String):Unit= {out(str)println(str)
}
/**
在Scala中它可以将尾递归转换成循环。就不会出现栈溢出了。
* 尾递归:它把这个递归函数,若最后一条语句是递归本身。它可以把这种递归转成循环。就可以避免栈溢出。StackOverflowError(栈溢出异常)
*/
object TailRecursiveDemo{//用递归计算累加和,递归函数必须要定义返回值类型
def sum(list:List[Int]):Int={if(list.isEmpty)0 else list.head +sum(list.tail)//这里加了判断,它最后的语句就不是递归是0,所以不是尾递归
}//这个函数不是尾递归,为什么?因为它最后一条语句不是递归def main(args: Array[String]):Unit={val list=List(1 to 100:_*)println(sum(list))}
}

1.泛型

//定义泛型类
class Pair[T,S](val first:T,val second:S)
泛型的使用
object GenericTypeDemo{def main(args:Array[String]):Unit={//Pair[T,S]这个决定后面的属性:(var first:T,var second:S)是什么类型class Pair[T,S](var first:T,var second:S)//val p1=new Pair[Int,String](1,"tomas")//类型推断val p2=new Pair(1,"tomas")--------------------------------//方法定义泛型def middle[T](arr:Array[T]):T={arr(arr.length/2)}//调用函数var arr=Array(1,2,3,4)println(middle(arr)) //3//asInstanceOf这个也是泛型val obj=""obj.asInstanceOf[String]}
}
[Java里面的泛型]
public static T getMiddle(Listlist){return list.get(list.size()/2);
}
//调用java里面的泛型
【Maven】
junitjunit4.11

@Test
public void testMethod(){Listlist=new ArrayList();list.add(1);list.add(2);list.add(3);list.add(4);System.out.println(getMiddle(list)); //2
}
//在方法调用中指定类型,通过对象来调用
public static T getMiddle(Listlist){return list.get(list.size()/2);
}
@Test
public void testMethod(){Listlist=new ArrayList();list.add(1);list.add(2);list.add(3);list.add(4);//在方法调用中指定System.out.println(getMiddle(list));
}

2.类型变量的界定

类型变量界定:指的就是范围(上限和下限)
现在你想要添加一个方法,产生较小的那个值:产生较小值的话。它要能够比较大小
class Pair[T](val first:T,va; second:T){//在上面直接定义了一个T作为一个泛型&#xff0c;在方法体中first.compareTo(second)<0)小于他&#xff0c;小于0就返回。就是T或者first是否有没有这个方法&#xff1f;它不一定有。所以它可能是错的。为了保证它一定有可以添加添加一个上界T<:Comparable[T]> 上限&#xff0c;就是要小于T<:Comparable[T]> def smaller&#61;if(first.compareTo(second)<0)first else second //错误
}
这是错的----我们并不知道first是否有compareTo方法。要解决这个问题&#xff0c;我们可以添加一个上界T<:Comparable[T]> 上限//定义上界限
//class Pair[T ](var first:T,var second:T){//它没有<:Comparable[T]识别不了
class Pair[T <:Comparable[T]](var first:T,var second:T){//定义一个方法要取&#xff0c;取它两个大的值。T//获取两个属性中较大的一个def max():T&#61;{if&#xff08;first.compareTo(second)>0&#xff09;first else second;}
}
val p1&#61;new Pair(100,200)//报错&#xff0c;它不能比较大小在scala中它并没有Comparable
val p1&#61;new Pair("100","200")//200
//注意了在Java里面和scala里面字符窗String 有什么区别
type String &#61;java.lang,String //scala里面的串就是java里面的串&#xff0c;它就是一个别名
type Class[T]&#61;java.lang.Class[T]
println(p1.max())
Int的是AnyVal&#xff0c;Int的不是别名。它没有Comparable的特点。所以它比较不了。
如果要向实现数字的大小比较&#xff0c;需要用到视图界定
[Int的源码翻看]
final abstract class Int private etends AnyVal{}
//考察下界
class Animal
class Dog extends Animal
class Jing8 extends Dog
//T&#xff0c;没有任何说法&#xff0c;什么都可以
//Pari是有两个属性的&#xff0c;都是T类型.现在添加一个方法将first替换掉&#xff0c;保留第二个不变第一个变掉
class Pair[T](var first &#xff1a;T&#xff0c;var second:T){//R需要是T的超类//def replaceFirst[R >:T](newele:R)&#61;{def replaceFirst[R >:T](newfirst:R)&#61;{//new Pair(newele,second)new Pair(newfirst,second)}
}
val d1&#61;new Dog()
val d2&#61;new Dog()
val p1&#61;new Pair[Dog](d1,d2)
val jing8&#61;new Jing8()
val p2&#61; p1.replaceFirst(jing8)
//加了泛型它就有要求&#xff0c;需要给方法显示指定泛型
val p2&#61; p1.replaceFirst[Jing8](jing8)
//给它一个新的类型
val a1&#61;new Animal()
p1.replaceFirst[Animal](a1)
println(p2)1.类上泛型class Pair[T,S](var first:T , var second:S) val p &#61; new Pair[Int,String](100,"tom")val p &#61; new Pair(100,"tom")2.方法上泛型def mid[T](arr:Array[T]) &#61; arr(arr.length / 2)mid[Int](Array(2,3,4))mid(Array(2,3,4))3.类型上限界定class Pair[T <: Comparable[T]] (var a:T ,var b:T)val p &#61; new Pair("100","100")4.类型下限界定class Pair[T >: Jing8](var fst:T ,var sec:T){// 替换一个新的元素 ele:R代表ele的元素类型是R类型。def replaceFirst[R >: T](ele:R) {//new Pair(ele , sec) ;表示下界&#xff0c;R必须是父类才可以new Pair(ele , sec) ;//把原sec放这替换ele}}val d1 &#61; new Dog()val d2 &#61; new Dog()val p1 &#61; new Pair(d1,d2)//val jing8 &#61; new Jing8()//错误&#xff0c;jing8是dog的子类&#xff0c;不符合下界范围p1.replaceFirst[Jing8](jing8)//替换&#xff0c;必须要把泛型写上[Jing8]val a1 &#61; new Animal()//OK , 符合下界范围p1.replaceFirst[Animal](a1)

3.视图界定

视图界定<% //相当于模糊查询&#xff0c;能够隐式转换成目标类
class Pair[T<% Comparable[T]](var first:T,var second:T){//获取两个属性中较大的一个def max():T&#61;{if(first.compareTo(second)>0)first else second;}
}<% //相当于模糊查询&#xff0c;能够隐式转换成目标类也可以。class Pair[T <% Comparable[T]] (var a:T , var b:T)val p &#61; new Pair(100,200)
上下文界定视图界定T<%V要求必须存在一个从T到V的隐式转换。上下文界定的形式为T&#xff1a;M&#xff0c;其中M是另一个泛型类。它要求必须存在一个类型为M[T]的"隐式值"。class Pair[T:Ordering] //Ordering必须存在隐式值才行

4.多重界定

先大于后小于//R>:Jing8 <:Animal,
类型变量可以同时有上界和下界。写法为&#xff1a;T>:Lower <:Upper
class Animal
class Dog extends Animal
class Cat extends Animal
class JiaFeiCat extends Catclass Jing8 extends Dog
class LocalJing8 extends Jing8class Pair[T](var first:T,var second:T){//现在的要求就是替换的数它得是Animal的子类同时也是LocalJing8的父类def replaceFirst[R <:LocalJing8<:Animal ](ele:R)&#61;{new Pair(ele,second)}
}
val a1&#61;new Animal
val d1&#61;new Dog
val d2&#61;new Dog
val jing81&#61;new Jing8()
val jing82&#61;new Jing8()
val local1&#61;new LocalJing8()
val local2&#61;new LocalJing8()
val c1&#61;new Cat()val p1&#61;new Pair[Dog](d1,d2)
//对它进行替换&#xff0c;它必须是Animal的子类LocalJing8的父类
val pp&#61;p1.replaceFirst[Animal]&#xff08;a1&#xff09; //动物本身可以
val pp&#61;p1.replaceFirst[Cat]&#xff08;C1&#xff09;//do not conform to method replaceFirst&#39;s type parameter bounds 它不符合参数类型的边界
val pp&#61;p1.replaceFirst[LocalJing8]&#xff08;local1&#xff09;//可以进来了&#xff0c;它是包含的
println(pp) //200
//就定义一个Jing8是不可以的def replaceFirst[R <:Jing8<:Animal ](ele:R)&#61;{
def replaceFirst[R <:Jing8<:Animal ](ele:R)&#61;{new Pair(ele,second)}
val p1&#61;new Pair[Dog](d1,d2)
val pp&#61;p1.replaceFirst[LocalJing8](local1)
println(pp)//do not conform to method replaceFirst&#39;s type parameter bounds 它不符合参数类型的边界//R >: Jing8 <: Animal , 先大于后小于。class Pair[T] (var first:T , var second:T) {//能传给方法给replaceFirst的是谁&#xff1f;def replaceFirst[R >: LocalJing8 <: Animal] (ele :R) &#61; {new Pair(ele, second) ;}}

5.型变

class Person
class Student extends Person
class Teacher extends Personclass Pair[T](var first:T,val second:T){def makeFriends(frd:Pair[Person])&#61;{println("hello world")}
}
val p1&#61;new Pair[String]("bob","alice")
val p2&#61;new Pair[Person](new Person,new Person)
如果Student是Person的子类&#xff0c;那么我可以用Pair[Student]作为参数调用makeFriends吗&#xff1f;
缺省情况下&#xff0c;这是个错误。尽管Student是Person的子类型&#xff0c;但Pair[Student]和Pair[Person]之间没有任何关系。现在是让Person和Student之间有继承关系。
p1.makeFriends(p2)1)协变&#xff0c;就是变化方向相同[&#43;T]就是协变按照相同方向改变。class Personclass Student extends Personclass Teacher extends Person//协变&#xff0c;变化方向相同class Pair[&#43;T](val first: T, val second: T) {//Person和Student是有继承关系的和Pair和Person&#xff0c;Student没有继承关系&#xff0c;如果要想有这样的关系就编写在定义Pair类时表明这一点class Pair[&#43;T](val first:T,val second:T)def makeFriends(frd : Pair[Person]) &#61; {println("hello world")}}val p1 &#61; new Pair[Person](new Person , new Person)val p2 &#61; new Pair[Student](new Student , new Student)p1.makeFriends(p2)2)逆变 Student是Person的子类Pair Person类的父类成相反方向变换.Pair[Student]是Pair[Person]的父类。

6.隐式转换

隐式转换函数&#xff08;implicit convcrsion function&#xff09;指的是那种以implicit关键字声明的带有单个的函数。这样的函数将被自动应用&#xff0c;将指从一种类型转换为另一种类型

/**隐式转换测试
*/
object ConvertDemo{def main(args:Array[String]):Uint&#61;{//定义分数类// case class Fraction(val top:Int,val bot:Int){// def mulby(f2:Fraction)&#61;{// Fraction(top*f2.top,bot*f2.bot)// }}//定义隐式函数implicit def int2Frction(n:Int)&#61;{Fraction(n,1)}val f1&#61;Fraction(1,2)val f2&#61;Fraction(2,3)val f3&#61;Fraction(f2)println(f3) //Fraction&#xff08;2&#xff0c;6&#xff09;println(f3.mulby(4)) //Fraction&#xff08;8&#xff0c;6&#xff09;//如果你函数的参数只有一个&#xff0c;那你就可以把这个方法变成操作符放中间。println(f3 mulby 4)//典型的中置 //Fraction&#xff08;8&#xff0c;6&#xff09;}
}
工作原理&#xff1a;都是引进了一些隐式转换函数&#xff0c;当你把不符合条件的参数变成符合条件的对象
[工具类]
//object 是单例对象 里面的方法都是静态的
object MyConverterUtil{implicit def int2Fraction(){}
}[JavaConversions(scala.collection)源码解析]
Object JavaConversions extends WrapAsScala with WrapAsJava
里面定义了很多隐式转换
implicit def as ScalaIterator[A](it:ju.Iterator[A]):Iterator[A]&#61;it match{case IteratorWrapper(wrapped)&#61;>wrappedcase _&#61;>JIteratorWrapper(it)
}
..
//常用的 它的参数是List ju&#61;java.util
//可以这样引用命名空间 import java.{lang &#61;>jl,util&#61;>ju},java.util.{concurrent&#61;>jc}
implicit def asScalaBuffer[A](l:ju.List[A]):mutable.Buffer[A]&#61;l match{case MutableBufferWrapper(wrapped)&#61;>wrappedcase _&#61;>new JListWrapper(l)
}
[RichInt(RichInt(scala.runtime))]//这个类是可以比较大小的。
//RichInt实现了ScalaNumberProxy&#xff0c;它实现了scala数字的代理。它就可以比较大小
final class RichInt(val self:Int)extends AnyVal with ScalaNumberProxy[Int]with RangedProxy[Int]{}
//Comparable有序的
trait Ordered[A]extends Any with java.lang.Comparable[A]{}
//Ordered的类型就是
type Ordered[T]&#61;scala.math.Ordered[T]
val Numeric&#61;scala.math.Ordered
//OrderedProxy这个是代理&#xff0c;Ordered它有接口的实现
trait OrderedProxy[T]extends Any with Ordered[T]with Typed[T]{protected def ord:Ordering[T]def compare(x:T)&#61;ord.compare(self,y)
}Int.scala
implicit scala.language.implicitConversions //implicitConversions隐式转换引入隐式转换导包&#xff1a;
import com.horstmann.impatient.FractionConversions._
在导的时候可以带下划线&#xff0c;也可以导具体的方法。
import MyCoverterUtil //如果不想全部导进来就可以导局部的
import MyCoverterUtil.int2Fraction //导入具体的隐式转换函数。//隐式值测试
object ImplictValueDemo{def main(args:Array[String])&#61;{//修饰函数def decorate(pref&#xff1a;String&#61;"<<<",str:String,suf:String&#61;">>>")&#61;{pref&#43;str&#61;suf}////带名参数println(decorate(str&#61;"hello"))//假如你有很多方法都有implicit这个类型的参数&#xff0c;在绝大多数情况下都以这个值做为参数传递。就可以把这个值定义为默认值。隐式参数是不 可以完成作业的&#xff0c;它一定要跟隐式值配合。def decorate(implicit pref:String,str:String)&#61;{pref&#43;str}//抛异常&#xff1a;//如果在引入隐式转换的时候&#xff0c;有多个的时候&#xff0c;会报异常。此时可以引具体的方法import MyConverterUtil.prefixprintln(decorate(str&#61;"hello"))//implicit val&#43;字符串pref:String就成了隐式值implicit val pref:String&#61;"<<<"println(decorate())}
}典型的
val list&#xff1a;List[Int]&#61;List(1 to 10:_*)
//implicit bf隐式参数就可以找到一个隐式值将它传进来。这也是柯里化(一次只处理一个参数)的好处。隐式参数定在一起没法弄。
//map[B,That](f:(String)&#61;>B)(implicit bf&#xff1a;CanBuildFrom[List[String],B,That])That
list.map(_*2)
1.隐式转换函数 object Utils{implicit def int2Fraction(n:Int) &#61; {Fraction( n, 1)}}import Utils._3 * Fraction(1,2)2.隐式参数//柯里化函数implicit val pref:String &#61; "<<<"def dec(str:String)(implicit pre:String)dec("hello")3.隐式值implicit val xx:String &#61; "<<<"def dec("hello")

7.SAM

SAM&#xff08;函数在java里面就是接口&#xff09;&#xff08;隐式转换函数的应用&#xff09;single abstract method&#xff08;单个抽象方法&#xff09;
object SAMDemo{//每次实现奇数加1var click:Int&#61;0def main(args:Array[String]):Unit&#61;{val frame&#61;new JFrame()frame.setTitle("hello swing")frame.setBounds(50,50,200,100)frame.setVisible(true)//加按钮之前设置一下布局为空frame.setLayout(null);val btn&#61;new JButton()btn.setBounds(0,0,100,50)btn.setText("ok")//实现点击一下加1btn.addActionListener(new ActionListener{//ActionListener public interface ActionListener extends EventListener 它就一个 public void actionPerformed&#xff08;ActionEvent e&#xff09;抽象方法。。典型的匿名类对象override def actionPerformed(e:ActionEvent)&#61;{//常规的Java实现//给按钮一个点击事件&#xff0c;每次点击一下加1 &#xff0c;scala可以做sam抽象&#xff0c;一个抽象方法click&#43;&#61;1println(click) //1,2,3,,4,5,6,,7,....15}})//(e:ActionEvent)&#61;>{click_&#43;&#61;1;println(click)这个传的是一个函数&#xff0c;而不是需要的事件监听器。为了让这种方式成为可能&#xff0c;就要做一个隐式转换。隐式转换就是直接能把(e:ActionEvent)&#61;>{click_&#43;&#61;1;println(click)转换成ActionListener实现就可可以了// btn.addActionListener((e:ActionEvent)&#61;>{click_&#43;&#61;1;println(click)})//从函数到func2ActionLisnter的转换func2ActionLisnter&#xff08;&#xff09;的参数是一个函数&#xff0c;{click_&#43;&#61;1;println(click)函数本身没有返回值。参数是ActionEvent类型//定义隐式转换函数&#xff0c;将函数转换成actionListen对象&#xff08;SAM转换&#xff09;implicit def func2ActionListnter(f:(ActionEvent)&#61;>Unit)&#61;{new ActionListener{override def actionPerformed(e:ActionEevent)&#61;{f(e)}}}btn.addActionListener((e:ActionEvent)&#61;>{click&#43;&#61;1;println(click)});frame.add(btn)//frame.setVisible(true)}
}

转:https://www.cnblogs.com/SteveDZC/p/9771241.html



推荐阅读
author-avatar
勇气的爱_961
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有