scala高级类型

Posted 拱头

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)







以上是关于scala高级类型的主要内容,如果未能解决你的问题,请参考以下文章

23.scala的自类型

19.scala的类型上下界

scala-协变逆变上界下界

scala-协变逆变上界下界

Scala语法详解:特质 (Traits)

17. Scala泛型上下界视图界定上下文界定