scala 高级类型

一 单例类型 this.type

Scala中,对于任何类型的引用v,都可以调用v.type,然后会返回v或者null,有时候这种是有用的,假设一下场景:

比如某一个方法返回this,

class Person {
    private var name:String = null
    private var age
:Int = 0
   
def setName(name:String)={
        this.name=name
       
//返回对象本身
       
this
   
}
    def setAge(age:Int)={
        this.age=age
       
//返回对象本身
       
this
   
}
    override def toString()="name:"+name+" age:"+age
}

那么我们就可以完成链式调用,如:

object Test extends App {
    /**
     * 报错是因为返回的this代表的是父类自己而不是子类自己,而弗雷是没有setStudentNo方法的
     * 为解决该问题,可以将setNamesetAge方法的返回值设置为:this.type
     */
    println(new Person().setName("john").setAge(22).setStudentNo("2014"))
}

 

然而,如果你还有个子类:

/*当涉及到继承时,会存在一些问题*/
class Student extends Person{
    private var studentNo:String = null
    def setStudentNo(no:String) = {
        this.studentNo=no
        this
    }
    override def toString() = super.toString()+" studetNo:"+studentNo
}

然后再来链式调用,就会有问题:

object Test extends App {
    /**
     * 报错是因为返回的this代表的是父类自己而不是子类自己,而弗雷是没有setStudentNo方法的
     * 为解决该问题,可以将setNamesetAge方法的返回值设置为:this.type
     */
    println(new Student().setName("john").setAge(22).setStudentNo("2014"))
}

 

解决办法:

class Person {
    private var name:String = null
    private var age:Int = 0
    def setName(name:String):this.type = {
        this.name=name
        //返回对象本身
        this
    }
    def setAge(age:Int):this.type={
        this.age=age
        //返回对象本身
        this
    }
    override def toString()="name:"+name+" age:"+age
}

 

二 类型投影

问题描述,不同对象创建的内部类不是同一种类型:

import scala.collection.mutable.ArrayBuffer
class NetWork {
    class Member(val name:String){
        val contacts = new ArrayBuffer[Member]()
    }
    private val members = new ArrayBuffer[Member]
    def join(name:String) = {
        val m = new Member(name)
        members += m
        m
    }
}

object Test extends App{
    val chatter = new NetWork
    val myFace = new NetWork

    /**
     * 现在chatter.Member myFace.Member和是不同的
     * 你不可以将其中一个member添加到另外一个member
     */
    val fred = chatter.join("Fred")
    val banery = myFace.join("Banery")
    //这样是有问题的
    fred.contacts += banery
}

如果要解决这个问题,可以使用类型投影:

类型投影的目的是将外部类定义的方法中,他可以接收任意外部类对象的内部类。

也就是说newchatter.Member 和 new myFace.Member()虽然是属于不同的类,但是他们有着共同父类NetWork#Member,我们对之前的代码稍加改造:

class NetWork {
    class Member(val name:String){
        val contacts = new ArrayBuffer[NetWork#Member]()
    }

    private val members = new ArrayBuffer[NetWork.this.Member]
    def join(name:String) = {
        val m = new Member(name)
        members += m
        m
    }
}

 

三 类型别名

对于复杂的类型,你可以使用type关键字创建一个简单的别名,就像这样:

 

四 结构类型

结构类型利用反射机制为静态语言添加动态性,从而使得参数类型不受限于某个已命名的类型,比如:

class StructType {
    /**
     * 1 语法:def 函数名(变量名:{抽象函数},其他参数列表)
     * 2 {抽象函数}就表示结构体
     * 3 结构体还可以使用type关键字声明 type func = {抽象函数}
     * 4 在函数体内就可以调用=> 变量名.抽象函数()
     * 5 在调用主题函数的时候,需要使用new {抽象函数的实现}
     * 6 所以感觉上结构体也是一个特殊的类
     */
    def appendLines(target:{def append(line:String):Any},lines:Iterable[String]): StringBuilder ={
        val sb = new StringBuilder()
        for (l <- lines){
            val s = target.append(l)
            sb.append(s).append("\n")
        }
        sb
    }
}

object Test1 extends  App{
    val st = new StructType
    val animals = List("tiger","lions","hadoop")

    val sb = st.appendLines(new {def append(line:String):Any = {"<"+line.toUpperCase()+">"}},animals)
    sb.foreach(e => print(e))
}

<TIGER>

<LIONS>

<HADOOP>

另外结构体还可以使用type关键字声明:

class StructType {

    type append_func = {def append(line:String):Any}
    def appendLines(target:append_func,lines:Iterable[String]): StringBuilder ={
        val sb = new StringBuilder()
        for (l <- lines){
            val s = target.append(l)
            sb.append(s).append("\n")
        }
        sb
    }
}

object Test1 extends  App{
    val st = new StructType
    val animals = List("tiger","lions","hadoop")

    val sb = st.appendLines(new {def append(line:String):Any = {"<"+line.toUpperCase()+">"}},animals)
    sb.foreach(e => print(e))
}

 

五 复合类型

语法格式: T1 with T2with T3

其中T1,T2,T3是类型,要想成为该复合类型的实例,某一个值必须满足每一个类型要求才行,因此这样的类型也被称作为交集类型

你可以用复合类型来操纵那些必须提供多个特质的值,比如:

class A {
    def show(desc:String): Unit ={
        println(desc)
    }
}

trait B {
    def toUpper(message:String):String
}

/**
 * 现在这个类就是ASerializable的复合类型
 * 注意:
 * with 必须是trait或者java的接口,不能是scala的类或者java
 * 就算是抽象类也不行
 */

class ComplexType extends A with java.io.Serializable with B {
    override def toUpper(message: String): String = {
        message.toUpperCase()
    }
}

 

我们可以利用关键字type声明一个复合类型

class ComplexType {
    type Type = A with java.io.Serializable with B
    def func(t:Type): Unit ={
        t.show("I love you")
    }
}

 

六 中置类型

中置类型是一个带有两个类型参数的类型,以中置语法表示,类型名称写在两个类型参数之间,举例来说,你可以这样写:

String Map Int 而不是Map[String,Int]

case class InfixType[S,T](val name:S,val age:T) {

}

object InfixType extends App{
    //我么一般这么写:
    val infix1:InfixType[String,Int] = InfixType[String,Int]("Infix",28)
    //使用中置表达式写法
     val infix2:String InfixType Int = InfixType("Infix",28)
}

 

七 存在类型

存在类型的语法 [类型表达式] forsome {type T}

forSome使得我们能够使用更加复杂的关系,比如Map[T,S]

forSome {type T;type S <: T},而不仅限于类型通配符能表达的那些

 

class ExistsType {
    def func1[T](ele:Array[T] forSome {type T}):Unit = {
        ele.foreach(e => print(e+" "))
    }

    def func2(ele:Array[_]):Unit = {
        ele.foreach(e => print(e+" "))
    }

    //Map[_,_]相当于Map[T,U] forSome {type T;type U}
    def func3[T,S](dict:Map[T,S] forSome {type T;type S}): Unit ={
        for((k,v) <- dict){
            print(k,v)
        }
    }
    def func4(dict:Map[_,_]): Unit ={
        for((k,v) <- dict){
            print(k,v)
        }
    }
}

 

八  自身类型

我么知道,我们可以限制混入特质的时候,限定类型。

通过语法this:指定类型 => 然后指定所允许混入的类或者其子类才可以混入该trait

 

class BaseType
class ParentType
trait MyTrait {
    /**
     * 指定该trait只能被BaseType的子类可以混入
     * 不是BaseType的子类是不可以混入这个trait
     */

    this:BaseType =>
}

class ConcreteType extends BaseType with MyTrait
/*所以这里会报错*/
class ImplementType extends  ParentType with MyTrait

 

九 抽象类型

抽象类型:是指在类或者特质中利用type关键字定义一个没有确定类型的标识,该标志在子类被确定,称这种类型为程序类型,比如:

abstract class Persons{
    //声明一个未被确定的类型
    type UndefinedType
    def show(x:UndefinedType)
}

class Students extends Persons{
    //确定抽象类型
    type UndefinedType = String
    def show(x:UndefinedType):Unit = {
        println("Student show => "+ x.toLowerCase())
    }
}

class Teachers extends Persons{
    type UndefinedType = mutable.HashMap[String,String]
    def show(x:UndefinedType):Unit = {
        for ((k,v) <- x){
            println("Teacher show key => "+k+" value=>"+v)
        }
    }
}

object AbstractType extends App {
    val message = "Welcome You, Guys"
    val map = mutable.HashMap(("Nicky", "Math"), ("Allice", "History"), ("Judy", "English"))
    val s = new Students
    s.show(message)
    val t = new Teachers
    t.show(map)
}

上述代码的也可用泛型进行实现,如:

abstract class People[T]{
    def show(x:T)
}

class Worker extends People[String]{
    def show(x:String):Unit = {
        println("Student show => "+ x.toLowerCase())
    }
}

class Leader extends People[mutable.HashMap[String,String]]{
    def show(x:mutable.HashMap[String,String]):Unit = {
        for ((k,v) <- x){
            println("Teacher show key => "+k+" value=>"+v)
        }
    }
}

 

结论:

在实际应用中,如果类型是在实例化的时候给定的,推荐用类型参数进行类的定义;如果类型是在子类型中才被确定,则推荐使用抽象类型。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值