scala高级类型

泛型

泛型相关类
ClassTag
这个类就是泛型类的类型。
泛型类在实例化的时候一定要具体指名泛型类型,泛型在编译的时候信息是抹去的,就会存在以下问题:
def mkArray[T](elem:T*) = Array[T](elem:_*)//编译阶段会报错
上面这句在编译的时候是报错的,因为Array[T]没有指定类型,但是我们有时候要这么写代码怎么办呢?这时候就要用到ClassTag,ClassTag会在编译阶段将泛型的信息保存下来:
def mkArray[ T :ClassTag](elem: T*) = Array[ T](elem:_*)
以上这样定义就没有问题

Manifest
这个类很少用。现在知道的用法和上面的相似
>: 和 <:
以上两个符号用来界定泛类型的上下界:
//定义了泛类型的上界(父类)
class Pair[ T <: Comparable[ T]]( val first: T, val second: T){
def bigger = if(first.compareTo(second) > 0) first else second
}

class Pair_Lower_Bound[ T]( val first: T, val second: T){
//定义了泛类型的下界(子类)
def replaceFirst[ R >: T](newFirst: R) = new Pair_Lower_Bound[ R](newFirst,second)
}

object Type_Variables_Bounds {

def main(args: Array[ String]) {
val pair = new Pair( "Spark", "Hadoop")
println(pair.bigger)
}
}
<% 和 >%
以上两个符号称作视图界定
//class Pair_NotPerfect[T <: Comparable[T]](val first:T,val second:T){
// def bigger = if(first.compareTo(second) > 0) first else second
//}

class Pair_NotPerfect[ T <% Comparable[ T]]( val first: T, val second: T){
def bigger = if(first.compareTo(second) > 0) first else second
}

object View_Bounds {

def main(args: Array[String]) {
val pair = new Pair_NotPerfect(2,3) //Int -> RichInt
println(pair.bigger)
}
}
注意:要是黄底的部分没有注释掉,使用黄底部分的定义的话,下面黄底的部分是会报错的。因为Int类型并没有实现Comparable,但是使用<%后就会正确了,因为使用试图界定会将隐式转换传进来,如果隐式转换有几成Comparable就行了,就像这里的Int转成RichInt了。
<:<
以下两段代码的作用基本相同:
def rocky[T](i:T)(implicit en:T<:<java.io.Serializable): Unit ={
println( "aaaaa!!!!")
}

def rocky[T<:java.io.Serializable](i:T): Unit ={
println( "aaaaa!!!!")
}
+T 和 -T
协变和逆变,
协变:就是E是T的子类型那么A[E]是A[T]的子类型
逆变:就是E是T的子类型那么A[T]是A[E]的子类型
class Person
class Student extends Person
class C[ +T]( val arg: T)

trait Friend[ -T]{
def makeFriend(somebody: T)
}
object Vaniance {

def makeFriendWithYou(s:Student,f:Friend[Student]): Unit ={
f.makeFriend(s)
}

def main(args: Array[ String]) {
val value :C[Person] = new C[Student](new Student)

}
}
注意一下:java不能再泛型定义的时候界定协变和逆变,但是可以在使用的时候界定:
// List<? extends Object> list = new ArrayList<String>()
val list: List[_<:Any] = List[ String]()
注销掉的是java的代码,和下面没有注释的scala代码同义


单例类型v.type:
this.type的使用:
注意以下区别:
class Animal {def breathe = this}
class Cat extends Animal {def eat = this}
object Singleton_Types {

def main(args: Array[ String]) {
val cat = new Cat
cat.breathe .eat //这里报错了,因为breathe返回的类型是Animal,Animal中没有定义eat
}
}
解决以上问题,使用以下代码:
class Animal {def breathe:this.type = this}
class Cat extends Animal {def eat:this.type = this}
object Singleton_Types {

def main(args: Array[ String]) {
val cat = new Cat
cat.breathe. eat
}
}


类型投影:
类型投影就是类中的类:
class Outer {
private val x = 10
class Inner {
private val y = x + 10
}
}
投影类型会有一个路径问题,还是使用上面定义的代码:
val outer1 = new Outer
val outer2 = new Outer
var inner = new outer1.Inner
inner = new outer2.Inner //outer1.Inner和outer2.Inner不是同一个类型
标红的地方报错,因为outer1.Inner和outer2.Inner由于路径不同,并不是同一个类型。可以用Outer#Inner解决这个问题。
val o1 = new Outer
val o2 = new Outer
var i: Outer#Inner = new o1.Inner //前面用的Outer#Inner表示任何Outer的Inner
i = new o2.Inner


结构类型:
type关键字:
用法一:
type str = String
var a: str = _
a = "aaaa"
就是个类型加一个别名。
用法二:
class Structuralclass { def open() = println( "A class instance Opened!!!")}
object Structural_Type {

def main(args: Array[ String]) {
type X = { def open():Unit}
def init(rec: X) = rec.open()

//带open()方法的class
init( new Structuralclass)
//带open()方法的object
object A { def open() = println( "A single object Opened!!")}
init(A)
//使用匿名类
init( new { def open() = println( "Opened again!!!")})
}
}
这个用法的好处就是,我可以将所有含有open()方法的类型都传给init(),各个类型之间不需要有任何继承关系


中置类型:
带两个值得泛型类可以使用中置表达式:
例子:
class Infix_Type[ A, B]
val infix: Int Infix_Type String = null
val infix1: Infix_Type[Int, String] = null
上面2,3两行代码的作用是相同的,可以看到黄底的地方使用了中值表达式。


自身类型:
这里有两种用法
设置this的别名:
class Self {
self => //这一行的意思是定义self为this的别名
val tmp= "Scala"
def foo = self. tmp + this. tmp
}
这么做在使用内部类调用外部类的时候就会很方便:
class Outer { outer =>
val v1 = "Spark"
class Inner {
println(outer. v1)
}
}
限制类型可以混入的特质:
看以下代码:
trait Logged{
def log(msg: String)
}
trait LoggedException extends Logged{
this: Exception=> //只能混入Exception的子类
def logException(){
log(getMessage()) //这里使用到的getMessage()方法是Exception中的方法
}
}
这个时候我们需要混入LoggedException特质,如果使用以下代码会报错:
val ex = new JFrame( "ClassNotFoundException") with LoggedException{
override def log(msg: String): Unit = println(msg)
}
因为JFrame不是Exception的子类,不能混入LoggedException,只有Exception的子类才能混入,例如下面这样:
Exception的子类
val ex = new ClassNotFoundException( "ClassNotFoundException") with LoggedException{
override def log(msg: String): Unit = println(msg)
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值