zoukankan      html  css  js  c++  java
  • scala的泛型浅析

    1. scala泛型浅析

    package com.dtspark.scala.basics
    
    /**
     * 1,scala的类和方法、函数都可以是泛型。
     * 
    
     * 2,关于对类型边界的限定分为上边界和下边界(对类进行限制)
     * 上边界:表达了泛型的类型必须是"某种类型"或某种类型的"子类",语法为“<:”,
     * 下边界:表达了泛型的类型必须是"某种类型"或某种类型的"父类",语法为“>:”,
     * 
    
     * 3, "<%" :view bounds可以进行某种神秘的转换,把你的类型在没有知觉的情况下转换成目标类型,
     * 其实你可以认为view bounds是上下边界的加强和补充,语法为:"<%",要用到implicit进行隐式转换(见下面例子)
     * 
    
     * 4,"T:classTag":相当于动态类型,你使用时传入什么类型就是什么类型,(spark的程序的编译和运行是区分了Driver和Executor的,只有在运行的时候才知道完整的类型信息)
     * 语法为:"[T:ClassTag]"下面有列子
     *
    
     * 5,逆变和协变:-T和+T(下面有具体例子)+T可以传入其子类和本身(与继承关系一至)-T可以传入其父类和本身(与继承的关系相反),
     * 
    
     * 6,"T:Ordering" :表示将T变成Ordering[T],可以直接用其方法进行比大小,可完成排序等工作
     */
    
    class Person(val name:String){
      def talk(person:Person){
        println(this.name+" speak to "+person.name)
      }
    }
    
    class Worker(name:String) extends Person(name)
    
    class Dog(val name:String)
    
    
    
    
    //注意泛型用的是[]
    class Club[T<:Person](p1:T,p2:T){//"<:"必须是person或person的子类
      def comminicate = p1.talk(p2)
    }
    
    
    class Club2[T<%Person](p1:T,p2:T){
      def comminicate = p1.talk(p2)
    }
    
    class Engineer
    class Expert extends Engineer
    //如果是+T,指定类型为某类时,传入其子类或其本身
    //如果是-T,指定类型为某类时,传入其父类或其本身
    class Meeting[+T]//可以传入T或T的子类
    
    class Maximum[T:Ordering](val x:T,val y:T){
      def bigger(implicit ord:Ordering[T])={
        if(ord.compare(x, y)>0) x else y
      }
    }
    
    object HelloScalaTypeSystem {
      def main(args: Array[String]): Unit = {
         val p= new Person("Spark")
         val w= new Worker("Scala")
         new Club(p,w).comminicate
         
    //"<%"的列子
         //只是提供了一个转换的方法,在遇到<%时会调用,看dog是否被转换了。
         implicit def dog2Person(dog:Dog)=new Person(dog.name)
         val d = new Dog("dahuang")
         //注意必须强制类型转换,implicit中虽然是将dog隐式转换成person,
         //但是其实是对象擦除,变成了object,所以还要强制类型转换成person后才能使用
         //用[person]强制转换
         new Club2[Person](p,d).comminicate
         
     //-T +T例子,下面的participateMeeting方法指定具体是什么泛型
         val p1=new Meeting[Engineer]
         val p2=new Meeting[Expert]
         participateMeeting(p1)
         participateMeeting(p2)
     // T:Ordering 的例子   
         println(new Maximum(3,5).bigger)
         println(new Maximum("Scala","Java").bigger)
    
         
         
      }
      //这里指定传入的泛型具体是什么
      def participateMeeting(meeting:Meeting[Engineer])=  println("welcome")
      
    }
    

    T:ClassTag的例子(根据输入动态定义)

    命令行代码:

    scala> import scala.reflect.ClassTag
    import scala.reflect.ClassTag
     
    scala> def mkArray[T: ClassTag](elems: T*) = Array[T](elems: _*)
    mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]
     
     
    scala> mkArray(1,2,3)
    res1: Array[Int] = Array(1, 2, 3)
     
    scala> mkArray("ss","dd")
    res2: Array[String] = Array(ss, dd)
    scala> mkArray(1,"dd")
    res2: Array[Any] = Array(1, dd)
    

    2. scala 的作用域

    Scala的作用域并不特别,完全可以参考类似的C语言或者Java的作用域要求。
    简而言之就是:对于同名变量来说,大括号内部定义的变量会覆盖大括号外部的变量,局部变量覆盖成员变量,大括号内部import的类、变量、方法覆盖外部的。只有一种情况比较特殊,就是自身成员不会被import导入的成员覆盖。
    不过实际使用中并不会经常出现变量重名的情况,所以作用域的意义更多在于访问限制。这一条一般来说一句话就可以概括:作用域限定于定义或导入该变量或类的大括号及内层大括号嵌套中。
  • 相关阅读:
    Vue 实现前进刷新,后退不刷新的效果
    chrome浏览器的跨域设置——包括版本49前后两种设置
    Promise.all和Promise.race区别,和使用场景
    滚动条默认最底部
    使用react进行父子组件传值
    java 数组基础学习(一维二维数组)
    react项目 使用echarts
    Python的hasattr() getattr() setattr() 函数使用方法详解
    【线性判别】Fisher线性判别(转)
    【semantic segmentation】Pyramid Scene Parsing Network(转)
  • 原文地址:https://www.cnblogs.com/ios1988/p/7452398.html
Copyright © 2011-2022 走看看