欢迎加入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 |
带注解的类型 | T@A |
参数化类型 | 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,和连乐一起讨论学习!