跟连乐一起学Scala-高级类型

欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习!

单例类型

例子:

class Document{
    def setTitile(title: String) = {...; this}
    def setAuthor(author: String) = {...; this}
    ...
}

val atticle.setTitle("whatever floats your boat").setAuthor("lianle")

如果以上类有子类,会出现问题:

class Book extends Document{
    def addChapter(chapter: String) = {...; this}
    ...
}
//调用出错:
val book = new Book
book.setTitle("Scala for the impatient").addChapter("chapter1")

分析原因:

由于setTitle返回的是this;Scala将返回类型推断为Document,但是Document没有addChapter方法。

解决方法:

def setTitle(title: String) : this.type = {...; this}
//添加单例类型


类型投影

例子:

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
    }

}

定义两个网络:

val chatter = new Network
val myFace = new Network

如下操作会报错:

val fred = chatter.join("Fred")  //类型为chatter.Member
val barney = myFace.join("Barney")//类型为myFace.Member
fred.contacts += barney  //报错

解决方案:

class Network {
    class Member(val name: String) {
        val contacts = new ArrayBuffer[Network#Member]
        //以上意思是:“任何Network的Member”
    }
}


类型别名

对于复杂类型,你可以使用type关键字创建一个别名。

class Book {
    import scala.collection.mutable._
    type Index = HashMap[String, (Int, Int)]
    //之后,可以使用Index来代替HashMap了。
}

别名必须被嵌套在类或者对象中。



结构类型

所谓的”结构类型“指的是一组关于抽象方法、字段和类型的规格说明。这些抽象方法、字段和类型是满足该规格的类型必须具备的。

def appedLines(target: {def append(str: String): Any}, lines: Iterable[String]) {
    for(l <- lines){ target.append(1);target.append("\n")}
}

你可以对任何具备append方法的类的实例调用appendLines方法。



复合类型

定义形式:

T1 with T2 with T3 ...

例子:

val image = new ArrayBuffer[java.awt.Shape with java.io.Serializable]
Shape with Serializable {def contains(p: Point):Boolean}
//该类型的实例必须既是Shape的子类型也是Serializable的子类型。


中置类型

中置类型是一个带有两个类型参数的类型。

String Map Int
//String 和 Int类型的中置。
//类似数学中的A * B


存在类型

存在类型被加入Scala是为了与Java的类型通配符兼容。

定义形式:在类型表达式之后跟上forSome{…},花括号中包含了type和val的声明。

Array[T] forSome{ type T <: JComponent}
等价于:
Array[_ <: JComponent]
Array[_]
等价于:
Array[T] forSome{type T}
Map[_, _]
等价于:
Map[T, U] forSome {type T; type U}

forSome允许我们使用更复杂的关系,而不仅限于类型通配符能表达的那些。

Map[T, U] forSome {type T; type U <: T}



Scala类型系统

类型 语法举例
类或特质 class C…, trait C…
元组类型 (T1,T2,…Tn)
函数类型 (T1,T2…Tn) => T
带注解的类型 [email protected]
参数化类型 A[T1,T2…Tn]
单例类型 值.type
类型投影 O#I
复合类型 T1 with T2 with … with Tn{声明}
中置类型 T1 A T2
存在类型 T forSome {type 和val 声明}


自身类型

形式:

this: 类型 => 

举例:

trait Logged {
    def log(msg: String)
}
trait LoggedException extends Logged {
    this: Exception =>
    def log(){log(getMessage())}
    //可以调用getMessage,因为this是一个Exception
}


依赖注入

trait LoggerComponent {
    trait Logger {...}
    val logger: Logger
    class FileLogger(file: String) extends Logger {...}
}

trait Auth {
    this: LoggerComponent => //让我们可以访问日志器

    trait Auth{...}
    val auth: Auth
    class MockAuth(file: String) extends Auth {...}
    ...
}

组装配件:

object AppComponents extends LoggerComponent with AuthComponet {
    val logger = new FileLogger(text.log)
    val auth = new MockAuth("users.txt")
}


抽象类型

类或特质可以定义一个在子类中被具体化的抽象类型。

trait Reader {
    type Contents
    def read(fileName: String): Contents
}

实现:

class StringReader extends Reader {
    type Contents = String
    def read(fileName: String)  = Source.fromFile(fileName, "UTF-8").mkString
}

class ImageReader extends Reader {
    type Contents = BufferedImage
    def read(fileName: String) = ImageIO.read(new File(fileName))
}

另一个例子:

trait Reader[C]{
    def read(file: String) : C
}

class StringReader extends Reader[String] {
    def read(fileName: String) = Source.fromFile(fileName, "UTF-8").mkString
}

class ImageReader extends Reader[BufferdImage] {
    def read(fileName: String) = ImageIO.read(new File(fileName))
}

经验:

1.如果类型是在类被实例化时给出,则使用类型参数。

2.如果类型是在子类中给出,则适用抽象类型。



高等类型

泛型类型List依赖于类型T并产生一个特定的类型。

像List这样的泛型类型有时被称做类型构造器。

在Scala中,你可以定义出依赖于依赖其他类型的类型的类型。

欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 11:16:26

跟连乐一起学Scala-高级类型的相关文章

从零学scala(九)类型参数、高级类型

一:类型参数 泛型类 //泛型类,基本和java是一致的          class Pair[T,S](val first:T,val second:S) val pair1 = new Pair("42",42)          val pair2 = new Pair[Any,Any](42,"42") 泛型函数 //返回数组中间的值          def getMiddle[T](a:Array[T]) = a(a.length/2) def mai

scala一些高级类型

package com.ming.test import scala.collection.mutable.ArrayBuffer import scala.io.Source import java.awt.image.BufferedImage import javax.imageio.ImageIO import java.io.File /** * 高级类型 */ //单例类型,链式调用 class Document{ def setTitle(title:String)={this}

快学scala笔记.

第一章 基础 val 定义的值实际上是一个常量 var 声明其值可变的变量 val xmax,ymax = 100 var greeting,message: String = null 1.3 常用类型 Scala的7种数值类型:Byte.Char.Short.Int.Long.Float和Double 1.toString() 2.to(10) "Hello".intersect("World") 1.4 算术和操作符重载 val answer = 8 * 5

快学Scala课后习题答案

分享一个之前做快学Scala的课后习题(2-21章节,19无)的Github链接,我把习题的文字写在了每个回答的注释上面,这样方便大家对照着看,省的回过头去对照着pdf看了,如果有做的不对的地方希望大家给予指正. 链接如下,http://github.com/fxxkinglife/scala-hello. 举一个第二章节的例子, object charpter02 { /* * 2.1 * 一个数字如果为正数,则它的signum为1; * 如果是负数,则signum为-1; * 如果为0,则s

快学scala 第十一章 操作符 读书笔记及习题答案代码

chapter 11 操作符 标签:快学scala 一.笔记 scala种可以在反引号中包含几乎任何字符序列, val 'val' = 42 所有的操作符都是左结合的,除了以冒号(:)结尾的操作符,和赋值操作符.用于构造列表的::操作符是又结合的.1::2::Ni1的意思是1::(2::Ni1),先创建出包含2的列表,这个列表又被作为尾巴拼接到以1作为头部的列表中. 2. 函数调用语法:f(arg1, arg2,...)扩展到可以应用于函数之外的值,如果f不是函数或方法,那么这个表达式等于f.a

[Scala] 快学Scala A2L2

集合 13.1 集合的三大类 所有的集合都扩展Iterable特质.集合的三大集合为Seq, Set, Map Seq是一个有先后次序的值的序列,比如数组或列表.IndexSeq允许我们通过整型下表快速访问任意元素.但是链表不可以. Set是一组没有先后次序的值.SortedSet中,元素排过序. Map时一组(键,值)对.SortedMap按键排序 每一个Scala集合特质或类都有一个带有apply 方法的伴生对象. 13.2 可变和不可变集合 13.3 序列Sequence 不可变序列:In

跟连乐一起学Scala-集合

欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习! 集合 主要的集合特质 Seq 是一 个有先后次序的值的序列.比如数组和列表.IndexedSeq允许我们通过整型的下标快速的访问任意元素. Set 是一组没有先后次序的值.在SortedSet中,元素以某种排过序的顺序被访问. Map 是一组(键,值)对偶.SortedMap按照键的排序访问其中的实体. 序列 Vector是ArrayBuffer的不可变版本:一个带下标的序列,支持快速的随机访问. 向量是以树形结构的形式实现的

快学Scala 第十九课 (trait的abstract override使用)

trait的abstract override使用: 当我看到abstract override介绍的时候也是一脸懵逼,因为快学scala,只介绍了因为TimestampLogger中调用的super.log依旧是个abstract class,所以必须在方法前加上abstract和override.但是并没有具体介绍如何使用,然后查阅了其他文档,才明白使用方法. 下面的代码定义了超类LoggerEmpty,这个定义意味着该特质只能混入扩展LoggerEmpty的类中. 在特质中声明抽象方法中有

从C#到TypeScript - 高级类型

C# vs TypeScript - 高级类型 上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题. 联合类型 可以从字面上进行理解:其实就是多个类型联合在一起,用|符号隔开.如: string | number, 表示希望这个类型既可以是string,又可以是number.联合类型的字段只能调用这些类型共同拥有的方法,除非类型推论系统自动判断出真正的类型. //这里sn就是一个联合类型的字段,由于类型推论推断出s