scala 高级类型
来源:互联网 发布:人工智能如何实现 编辑:程序博客网 时间:2024/05/20 23:59
本文参考 《快学scala》第18章,这里列出来备忘:
内容为
1.单例类型可用于方法串接和带对象参数的方法。
2.类型投影对所有外部类型的对象都包含了其内部类的实例。
3.类型别名给类型指定一个短小的名称。
4.结构类型等效于“鸭子类型”。
5.存在类型为泛型类型的通配参数提供了统一形式。
6.使用自身类型来表明某特质对混入它的类或对象的类型要求。
7.“蛋糕模式”用自身类型来实例依赖注入。 *
8.抽象类型必须在子类中被具体化。
9. 高等类型带有本身为参数化类型的类型参数。
单例类型
给定任何引用v,你可以得到类型v.type,它有两个可能的值: v 和 null 。例如我们想让方法返回this,从而实现方法的串接调用:
01.
class
Document {
02.
def setTitle(title: String) = {...;
this
}
03.
def setAuthor(author: String) = {...;
this
}
04.
...
05.
}
06.
07.
// 级联使用
08.
val article =
new
Document
09.
article.setTitle(
'Whatever Floats Your Boat'
).setAuthor(
'Cay Horstmann'
)
不过,要是还有子类,问题就来了:
1.
class
Book
extends
Document {
2.
def addChapter(chapter: String) = {...;
this
}
3.
...
4.
}
5.
6.
val book =
new
Book()
7.
book.setTitle(
'Scala for the Impatient'
).addChapter(
'chapter1'
)
// error
由于setTitle返回的是this, Scala将返回类型推断为Document。但Document并没有addChapter方法。
解决方法是声明setTitle的返回类型为this.type :
1.
def setTitle(title: String):
this
.type = {...;
this
}
这样book.setTitle(“…”)返回类型就是book.type。
如果你想定义一个接受object实例作为参数的方法,你也可以使用单例类型。例如
01.
object Title
02.
03.
class
Document {
04.
private
var useNextArgAs: Any =
null
05.
def set(obj: Title.type):
this
.type = {useNextArgAs = obj;
this
}
06.
def to(arg: String) =
if
(useNextArgAs == Title) title = arg;
else
...
07.
...
08.
}
09.
10.
class
Book
extends
Document {}
11.
book.set(Title).to(
'Scala for the Impatient'
)
注意Title.type参数,你不能用:
1.
def set(obj: Title) ...
// error, Title代指的是单例对象,而不是类型
类型投影
在第5章的嵌套类中已经有过例子。http://blog.csdn.net/dwb1015/article/details/51706746
路径
形如: com.horstmann.impatient.chatter.Member 这样的表达式称之为路径。在最后的类型前,路径的所有组成部分都必须是“稳定的”,也就是说它必须指定到单个、有穷的范围。组成的部分必须是以下当中的一种:
- 包
- 对象
- val
- this、super、super[S]、C.this、C.super或C.super[S]
路径的组成部分不能是类。也不能是var。 例如:
1.
val aly =
new
Network.Member
// error Network是类
2.
3.
var chatter =
new
Network
4.
val fred =
new
chatter.Member
// error chatter不稳定
类型别名
对于复杂类型,你可以用type关键字创建一个简单的别名,这和C/C++的typedef相同。
1.
class
Book {
2.
import
scala.collection.mutable._
3.
type Index = HashMap[String, (Int, Int)]
4.
}
类型别名必须被嵌套在类或对象中。它不能出现在Scala文件的顶层。
结构类型
所谓的“结构类型”指的是一组关于抽象方法、字段和类型的规格说明,这些抽象方法、字段和类型是满足该规格的类型必须具备的。
1.
def appendLines(target: { def append(str: String): Any }, lines: Iterable[String]) {
2.
for
(l <- lines) { target.append(l); target.append('
3.
') }
4.
}
你可以对任何具备append方法的类的实例调用appendLines方法。这比定义一个有appendLines方法的特质更为灵活,因为你不能总是能够将该特质添加到使用的类上。
但是类型结构背后使用的是反射,而反射调用的开销比较大。因此,你应该只在需要抓住那些无法共享一个特质的类的共通行为的时候才使用结构类型。
复合类型
复合类型的定义形式如下:
1.
T1 with T2 with T3 ...
在这里,要想成为该复合类型的实例,某个值必须满足每一个类型的要求才行。例如:
1.
val image =
new
ArrayBuffer[java.awt.Shape with java.io.Serializable]
2.
3.
val rect =
new
Ractangle(
5
,
10
,
20
,
30
)
4.
image += rect
// OK , Rectangle是Serializable的
5.
image +=
new
Area(rect)
// error, Area是Shape但不是Serializable的
你可以把结构类型的声明添加到简单类型或复合类型。例如:
1.
Shape with Serializable { def contains(p: Point): Boolean}
该类型必须既是一个Shape的子类型也是Serializable的子类型,并且还必须有一个带Point参数的contains方法。
从技术上讲,
01.
// 结构类型
02.
{ def append(str: String): Any }
03.
// 是如下代码的简写
04.
AnyRef { def append(str: String): Any }
05.
06.
// 复合类型
07.
Shape with Serializable
08.
// 是如下代码的简写
09.
Shape with Serializable {}
中置类型
中置类型是一个带有两个类型参数的类型,以“中置”语法表示,类型名称写在两个类型参数之间。例如:
1.
String Map Int
2.
// 而不是
3.
Map[String, Int]
存在类型
存在类型被加入Scala是为了与Java的类型通配符兼容。存在类型的定义是在类型表达式之后跟上forSome{…},花括号中包含了type和val声明。例如:
1.
Array[T] forSome {type T <: JComponent}
2.
// 这与类型通配符效果相同
3.
Array[_ <: JComponent]
Scala的类型通配符只不过是存在类型的语法糖。例如:
1.
Array[_]
2.
// 等同于
3.
Array[T] forSome { type T }
4.
5.
Map[_, _]
6.
// 等同于
7.
Map[T, U] forSome { type T; type U }
你也可以在forSome代码块中使用val声明,因为val可以有自己的嵌套类型。例如:
1.
n.Member forSome { val n: Network}
Scala类型系统
自身类型
在第十章 http://blog.csdn.net/dwb1015/article/details/51761510 已经有过介绍。
注意: 自身类型不会自动继承, 你需要重复自身类型的声明:
1.
trait ManagedException
extends
LoggedException {
2.
this
: Exception =>
3.
...
4.
}
依赖注入
在Scala中,你可以通过特质和自身类型达到一个简单的依赖注入的效果。
01.
trait Logger {
02.
def log(msg: String)
03.
}
04.
05.
class
ConsoleLogger(str: String)
extends
Logger {
06.
def log(msg: String) = {
07.
println(
'Console: '
+ msg)
08.
}
09.
}
10.
11.
class
FileLogger(str: String)
extends
Logger {
12.
def log(msg: String) = {
13.
println(
'File: '
+ msg)
14.
}
15.
}
16.
17.
// 用户认证特质有一个对日志功能的依赖
18.
trait Auth {
19.
this
: Logger =>
20.
def login(id: String, pass
: String): Boolean
21.
}
22.
23.
// 应用逻辑有赖于上面两个特质
24.
trait App {
25.
this
: Logger with Auth =>
26.
...
27.
}
28.
29.
// 组装应用
30.
object MyApp
extends
App with FileLogger(
'test.log'
) with MockAuth(
'users.txt'
)
像这样使用特质的组合有些别扭。毕竟,一个应用程序并非是认证器和文件日志器的合体。更自然的表示方式可能是通过实例变量来表示组件。
蛋糕模式给出了更好的设计。在这个模式当中,你对每个服务都提供一个组件特质,该特质包含:
- 任何所依赖的组件,以自身类型表述。
- 描述服务接口的特质。
- 一个抽象的val,该val将被初始化成服务的一个实例。
- 可以有选择性的包含服务接口的实现。
01.
trait LoggerComponent {
02.
trait Logger { ... }
03.
val logger: Logger
04.
class
FileLogger(file: String)
extends
Logger { ... }
05.
...
06.
}
07.
08.
trait AuthComponent {
09.
this
: LoggerComponent =>
// 让我们可以访问日志器
10.
11.
trait Auth { ... }
12.
val auth: Auth
13.
class
MockAuth(file: String)
extends
Auth { ... }
14.
...
15.
}
16.
17.
// 使用组件
18.
object AppComponents
extends
LoggerComponent with AuthComponent {
19.
val logger =
new
FileLogger(
'test.log'
)
20.
val auth =
new
MockAuth(
'users.txt'
)
21.
}
抽象类型
类或特质可以定义一个在子类中被具体化的抽象类型。例如:
01.
trait Reader {
02.
type Contents
03.
def read(fileName: String): Contents
04.
}
05.
06.
class
StringReader
extends
Reader {
07.
type Contents = String
08.
def read(fileName: String) = Source.fromFile(filename,
'UTF-8'
).mkString
09.
}
10.
11.
class
ImageReader
extends
Reader {
12.
type Contents = BufferedImage
13.
def read(fileName: String) = ImageIO.read(
new
File(fileName))
14.
}
同样的效果可以通过类型参数来实现:
01.
trait Reader[C] {
02.
def read(fileName: String): C
03.
}
04.
05.
class
StringReader
extends
Reader[String] {
06.
def read(fileName: String) = Source.fromFile(filename,
'UTF-8'
).mkString
07.
}
08.
09.
class
ImageReader
extends
Reader[BufferedImage] {
10.
def read(fileName: String) = ImageIO.read(
new
File(fileName))
11.
}
那种方式更好呢?Scala经验法则:
- 如果类型是在类被实例化时给出,则使用类型参数。
- 如果类型是在子类中给出,则使用抽象类型。
抽象类型可以有类型界定,就和参数类型一样。例如:
01.
trait Listener {
02.
type Event <: java.util.EventObject
03.
...
04.
}
05.
06.
// 子类必须提供一个兼容的类型
07.
trait ActionListener
extends
Listener {
08.
type Event = java.awt.event.ActionEvent
09.
}
- scala高级类型
- scala 高级类型
- scala 高级类型
- scala高级类型
- Scala课堂-6-高级类型
- scala简要:高级函数和高级类型
- Scala入门之高级类型:类型投影
- Scala入门之高级类型:结构类型
- Scala School 笔记(五)--高级类型
- Scala入门之高级类型:this.type
- 快学Scala第18章----高级类型
- Scala高级特性中的类型参数总结(1)
- 快学Scala 第18章高级类型练习题
- Scala 类型
- Scala类型
- 快学Scala学习笔记及习题解答(17-18类型参数与高级类型)
- scala高级编程
- Scala list高级使用
- 【活动报名】还有三天!如何实现用户的快速增长 | 11Space拾壹谈第二期
- 常见的排序算法,Java实现
- Spring-AOP:简介
- Hadoop 日志文件分析
- NYOJ 269 VF
- scala 高级类型
- MQL5 命令行编译
- springmvc组件总结
- [docker]使用阿里云上面的私仓
- 算法-蓝桥杯习题(4-3)
- 启动系统安装程序开发指定文件,安装应用
- Qt::ConnectionType 解析
- validates的条件验证(if)的Proc用法
- 矩阵基础1010 UVA 11651 矩阵快速幂+DP 好题,推荐