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

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)			//ok

def 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>T getMiddle(List<T>list){
  return list.get(list.size()/2);
}
//调用java里面的泛型
【Maven】
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
</dependency>
@Test
public void testMethod(){
   List<Integer>list=new ArrayList<Integer>();
   list.add(1);
   list.add(2);
   list.add(3);
   list.add(4);
  System.out.println(getMiddle(list)); //2
}
//在方法调用中指定类型,通过对象来调用
public static <T>T getMiddle(List<T>list){
  return list.get(list.size()/2);
}
@Test
public void testMethod(){
   List<Integer>list=new ArrayList<Integer>();
   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作为一个泛型,在方法体中first.compareTo(second)<0)小于他,小于0就返回。就是T或者first是否有没有这个方法?它不一定有。所以它可能是错的。为了保证它一定有可以添加添加一个上界T<:Comparable[T]>  上限,就是要小于T<:Comparable[T]> 
  def smaller=if(first.compareTo(second)<0)first else second //错误
}
这是错的----我们并不知道first是否有compareTo方法。要解决这个问题,我们可以添加一个上界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){
  //定义一个方法要取,取它两个大的值。T
  //获取两个属性中较大的一个
  def max():T={
    if(first.compareTo(second)>0)first else second;
  }
}
val p1=new Pair(100,200)//报错,它不能比较大小在scala中它并没有Comparable
val p1=new Pair("100","200")//200
//注意了在Java里面和scala里面字符窗String 有什么区别
type String =java.lang,String //scala里面的串就是java里面的串,它就是一个别名
type Class[T]=java.lang.Class[T]
println(p1.max()) 
Int的是AnyVal,Int的不是别名。它没有Comparable的特点。所以它比较不了。
如果要向实现数字的大小比较,需要用到视图界定
[Int的源码翻看]
final abstract class Int private etends AnyVal{}
//考察下界
class Animal
class Dog extends Animal
class Jing8 extends Dog
//T,没有任何说法,什么都可以
//Pari是有两个属性的,都是T类型.现在添加一个方法将first替换掉,保留第二个不变第一个变掉
class Pair[T](var first :T,var second:T){
  //R需要是T的超类
  //def replaceFirst[R >:T](newele:R)={
  def replaceFirst[R >:T](newfirst:R)={
    //new Pair(newele,second)
    new Pair(newfirst,second)
  }
}
val d1=new Dog()
val d2=new Dog()
val p1=new Pair[Dog](d1,d2)
val jing8=new Jing8()
val p2= p1.replaceFirst(jing8)
//加了泛型它就有要求,需要给方法显示指定泛型
val p2= p1.replaceFirst[Jing8](jing8)
//给它一个新的类型
val a1=new Animal()
p1.replaceFirst[Animal](a1)
println(p2)

1.类上泛型
	class Pair[T,S](var first:T , var second:S) 
	val p = new Pair[Int,String](100,"tom")
	val p = new Pair(100,"tom")

2.方法上泛型
	def mid[T](arr:Array[T]) = 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 = 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) ;表示下界,R必须是父类才可以
			new Pair(ele , sec) ;//把原sec放这替换ele
		}
	}

	val d1 = new Dog()
	val d2 = new Dog()
	val p1 = new Pair(d1,d2)//
	val jing8 = new Jing8()
	//错误,jing8是dog的子类,不符合下界范围
	p1.replaceFirst[Jing8](jing8)//替换,必须要把泛型写上[Jing8]

	val a1 = new Animal()
	//OK , 符合下界范围
	p1.replaceFirst[Animal](a1)

3.视图界定

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


4.多重界定

 先大于后小于
 //R>:Jing8 <:Animal,
类型变量可以同时有上界和下界。写法为:
   T>:Lower <:Upper
class Animal
class Dog extends Animal
class Cat extends Animal
class JiaFeiCat extends Cat

class Jing8 extends Dog
class LocalJing8 extends Jing8

class Pair[T](var first:T,var second:T){
  //现在的要求就是替换的数它得是Animal的子类同时也是LocalJing8的父类
  def replaceFirst[R <:LocalJing8<:Animal ](ele:R)={
    new Pair(ele,second)
  }
}
val a1=new Animal
val d1=new Dog
val d2=new Dog
val jing81=new Jing8()
val jing82=new Jing8()
val local1=new LocalJing8()
val local2=new LocalJing8()
val c1=new Cat()

val p1=new Pair[Dog](d1,d2)
//对它进行替换,它必须是Animal的子类LocalJing8的父类
val pp=p1.replaceFirst[Animal](a1) //动物本身可以
val pp=p1.replaceFirst[Cat](C1)//do not conform to method replaceFirst's type parameter bounds 它不符合参数类型的边界
val pp=p1.replaceFirst[LocalJing8](local1)//可以进来了,它是包含的
println(pp) //200
//就定义一个Jing8是不可以的def replaceFirst[R <:Jing8<:Animal ](ele:R)={
def replaceFirst[R <:Jing8<:Animal ](ele:R)={
    new Pair(ele,second)
  }
val p1=new Pair[Dog](d1,d2)
val pp=p1.replaceFirst[LocalJing8](local1)
println(pp)//do not conform to method replaceFirst's type parameter bounds 它不符合参数类型的边界
	//R >: Jing8 <: Animal , 先大于后小于。
	class  Pair[T] (var first:T , var second:T) {
      //能传给方法给replaceFirst的是谁?
		def replaceFirst[R >: LocalJing8 <: Animal] (ele :R) = {
			new Pair(ele, second) ;
		}
	}

5.型变

class Person
class Student extends Person
class Teacher extends Person

class Pair[T](var first:T,val second:T){
  def makeFriends(frd:Pair[Person])={
    println("hello world")
  }
}
val p1=new Pair[String]("bob","alice")
val p2=new Pair[Person](new Person,new Person)
如果Student是Person的子类,那么我可以用Pair[Student]作为参数调用makeFriends吗?
缺省情况下,这是个错误。尽管Student是Person的子类型,但Pair[Student]和Pair[Person]之间没有任何关系。现在是让Person和Student之间有继承关系。
p1.makeFriends(p2)
	1)协变,就是变化方向相同[+T]就是协变
		按照相同方向改变。
		class Person
		class Student extends Person
		class Teacher extends Person

		//协变,变化方向相同
		class Pair[+T](val first: T, val second: T) {
			//Person和Student是有继承关系的和Pair和Person,Student没有继承关系,如果要想有这样的关系就编写在定义Pair类时表明这一点
          class Pair[+T](val first:T,val second:T)
			def makeFriends(frd : Pair[Person]) = {
				println("hello world")
			}
		}

		val p1 = new Pair[Person](new Person , new Person)
		val p2 = new Pair[Student](new Student , new Student)
		p1.makeFriends(p2)
		
	2)逆变  Student是Person的子类Pair Person类的父类
		成相反方向变换.
		Pair[Student]是Pair[Person]的父类。

6.隐式转换

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

/**
 隐式转换测试
*/
object ConvertDemo{
  def main(args:Array[String]):Uint={
    //定义分数类
  //  case class Fraction(val top:Int,val bot:Int){
  //    def mulby(f2:Fraction)={
   //      Fraction(top*f2.top,bot*f2.bot)
    //   }
    }
    //定义隐式函数
    implicit def int2Frction(n:Int)={
      Fraction(n,1)
    }
    val f1=Fraction(1,2)
    val f2=Fraction(2,3)
    val f3=Fraction(f2)
    println(f3)  //Fraction(2,6)
    println(f3.mulby(4))  //Fraction(8,6)
    //如果你函数的参数只有一个,那你就可以把这个方法变成操作符放中间。
    println(f3 mulby 4)//典型的中置 //Fraction(8,6)
  }
}
工作原理:都是引进了一些隐式转换函数,当你把不符合条件的参数变成符合条件的对象
[工具类]
//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]=it match{
  case IteratorWrapper(wrapped)=>wrapped
  case _=>JIteratorWrapper(it)
}
..
//常用的  它的参数是List ju=java.util
//可以这样引用命名空间    import java.{lang =>jl,util=>ju},java.util.{concurrent=>jc}
implicit def asScalaBuffer[A](l:ju.List[A]):mutable.Buffer[A]=l match{
  case MutableBufferWrapper(wrapped)=>wrapped
  case _=>new JListWrapper(l)
}
[RichInt(RichInt(scala.runtime))]//这个类是可以比较大小的。
//RichInt实现了ScalaNumberProxy,它实现了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]=scala.math.Ordered[T]
val Numeric=scala.math.Ordered
//OrderedProxy这个是代理,Ordered它有接口的实现
trait OrderedProxy[T]extends Any with Ordered[T]with Typed[T]{
  protected def ord:Ordering[T]
  def compare(x:T)=ord.compare(self,y)
}

Int.scala
implicit scala.language.implicitConversions //implicitConversions隐式转换

引入隐式转换导包:
import com.horstmann.impatient.FractionConversions._
在导的时候可以带下划线,也可以导具体的方法。
import MyCoverterUtil  //如果不想全部导进来就可以导局部的
import MyCoverterUtil.int2Fraction //导入具体的隐式转换函数。

//隐式值测试
object ImplictValueDemo{
  def main(args:Array[String])={
    //修饰函数
    def decorate(pref:String="<<<",str:String,suf:String=">>>")={
      pref+str=suf
    }
    //
 
    
    //带名参数
    println(decorate(str="hello"))
    //假如你有很多方法都有implicit这个类型的参数,在绝大多数情况下都以这个值做为参数传递。就可以把这个值定义为默认值。隐式参数是不 可以完成作业的,它一定要跟隐式值配合。
    def decorate(implicit pref:String,str:String)={
      pref+str
    }
    //抛异常:
    //如果在引入隐式转换的时候,有多个的时候,会报异常。此时可以引具体的方法
    import MyConverterUtil.prefix
    println(decorate(str="hello"))
    
    //implicit val+字符串pref:String就成了隐式值
    implicit val pref:String="<<<"
    println(decorate())
  }
}


典型的
val list:List[Int]=List(1 to 10:_*)
//implicit bf隐式参数就可以找到一个隐式值将它传进来。这也是柯里化(一次只处理一个参数)的好处。隐式参数定在一起没法弄。
//map[B,That](f:(String)=>B)(implicit bf:CanBuildFrom[List[String],B,That])That
list.map(_*2)
1.隐式转换函数  
	object Utils{
		implicit  def int2Fraction(n:Int) = {
			Fraction( n, 1)
		}
	}

	import Utils._
	3 * Fraction(1,2)
	2.隐式参数
	//柯里化函数
	implicit val pref:String = "<<<"
	def dec(str:String)(implicit pre:String)
	dec("hello")

3.隐式值
	implicit val xx:String = "<<<"
	def dec("hello")

7.SAM

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