在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

函数式编程与面向对象编程[4]:Scala的类型关联Type Alias

2016-8-29 13:15| 发布者: zhangjf| 查看: 591| 评论: 0

摘要: 函数式编程与面向对象编程:Scala的类型关联Type Alias 之剑 2016.5.4 23:55:19 类型关联 Type Alias type关键字 scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型。 ty ...
函数式编程与面向对象编程[4]:Scala的类型关联Type Alias

之剑 2016.5.4 23:55:19



类型关联 Type Alias type关键字

scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型。

type相当于声明一个类型别名:

  1. object TestMatrix extends App{
  2. type IntList = List[Int]
  3. //接下来就可以这样使用它:
  4. type Matrix = List[IntList]
  5. val m = Matrix( IntList(1,2,3),
  6. IntList(1,2,3),
  7. IntList(1,2,3))
  8. }
复制代码
  1. scala> type IntList=List[Int]
  2. defined type alias IntList
复制代码

这种给类型一个别名的特性只是一个小糖豆,不太甜,真正有趣的是给一类操作命名(联想C#中定义delegate)。

比如这样:

  1. type PersonPredicate = Person => Boolean
复制代码

接受一个Person,返回一个Boolean,我们把这一类用来判断一个人是否符合某个条件的操作统称为PersonPredicate。

然后我们可以定义以下predicate:

  1. val teenagerPred: PersonPredicate = person => person.age < 20
复制代码

然后前面写过的teenagers方法就可以这样重新定义:

  1. def teenagers(people: People): People = {
  2. people.filter(teenagerPred)
  3. }
复制代码

按照这个思路下去,我们就可以开始composite functions了。比如说,我们跟人收税,就可以这么做:

  1. type Tax = Person => Double
  2. val incomeTax: Tax = person => person.income * 5 / 100
  3. val kejuanzaTax: Tax = person => person.income * 20 / 100
  4. def giveMeYourMoney(p: Person) = {
  5. calculateTax(p, List(incomeTax, kejuanzaTax))
  6. }
  7. def calculateTax(person: Person, taxes: List[Tax]): Double = {
  8. taxes.foldLeft(0d) {
  9. (acc, curTax) => acc + curTax(person)
  10. }
  11. }
复制代码

总结一下type alia这个糖衣:

一个类型的type alias,类似于这样的:type t = x。编译器将在所有使用到t的地方把t替换为x。

对于一种操作的type alias,编译器将会根据参数列表和返回值类型的不同将其替换为对应的Function0,Function1,Function2 …… 一直到Function22。

如果我们真的定义一个超过22个参数的操作会如何呢?

  1. type twentyThree = (
  2. String, String, String, String,
  3. String, String, String, String,
  4. String, String, String, String,
  5. String, String, String, String,
  6. String, String, String, String,
  7. String, String, String
  8. ) => String
复制代码

Scala编译器会直接告诉我们: type Function23 is not a member of package scala

结构类型

结构类型(structural type)为静态语言增加了部分动态特性,使得参数类型不再拘泥于某个已命名的类型,只要参数中包含结构中声明的方法或值即可。举例来说,java里对所有定义了close方法的抽象了一个Closable接口,然后再用Closable类型约束参数,而scala里可以不要求参数必须继承自Closable接口只需要包含close方法;如下:

  1. scala> def free( res: {def close():Unit} ) {
  2. res.close
  3. }
  4. scala> free(new { def close()=println("closed") })
  5. closed
复制代码

也可以通过type在定义类型时,将其声明为结构类型

  1. scala> type X = { def close():Unit }
  2. defined type alias X
  3. scala> def free(res:X) = res.close
  4. scala> free(new { def close()=println("closed") })
  5. closed
复制代码

上面传入参数时,都是传入一个实现close方法的匿名类,如果某个类/单例中实现了close方法,也可以直接传入

  1. scala> object A { def close() {println("A closed")} }
  2. scala> free(A)
  3. A closed
  4. scala> class R { def close()=print("ok") }
  5. scala> val r = new R
  6. scala> free(r)
  7. ok
复制代码

结构类型还可以用在稍微复杂一点的“复合类型”中,比如:

  1. scala> trait X1; trait X2;
  2. scala> def test(x: X1 with X2 { def close():Unit } ) = x.close
复制代码

上面声明test方法参数的类型为:

  1. X1 with X2 { def close():Unit }
复制代码

表示参数需要符合特质X1和X2同时也要有定义close方法。

复合类型与with关键字
  1. class A extends (B with C with D with E)
  2. T1 with T2 with T3 …
复制代码

这种形式的类型称为复合类型(compound type)或者也叫交集类型(intersection type)。

跟结构类型类似,可以在一个方法里声明类型参数时使用复合类型:

  1. scala> trait X1; trait X2;
  2. scala> def test(x: X1 with X2) = {println("ok")}
  3. test: (x: X1 with X2)Unit
  4. scala> test(new X1 with X2)
  5. ok
  6. scala> object A extends X1 with X2
  7. scala> test(A)
  8. ok
复制代码

也可以通过 type 声明:

  1. scala> type X = X1 with X2
  2. defined type alias X
  3. scala> def test(x:X) = println("OK")
  4. test: (x: X)Unit
  5. scala> class A extends X1 with X2
  6. scala> val a = new A
  7. scala> test(a)
  8. OK
复制代码
结构类型

结构类型:定义方法或者表达式时,要求传参具有某种行为,但又不想使用类,或者接口去限制,可以使用结构类型。

  1. class Structural { def open()=print("A class instance Opened") }
  2. object Structural__Type {
  3. def main(args: Array[String]){
  4. init(new { def open()=println("Opened") }) //创建了一个匿名对象,实现open方法
  5. type X = { def open():Unit } //将右边的表达式命名为一个别名
  6. def init(res:X) = res.open
  7. init(new { def open()=println("Opened again") })
  8. object A { def open() {println("A single object Opened")} } //创建的单例对象里面也必须实现open方法
  9. init(A)
  10. val structural = new Structural
  11. init(structural)
  12. }
  13. def init( res: {def open():Unit} ) { //要求传进来的res对象具有open方法,不限制类型
  14. res.open
  15. }
  16. }
复制代码

Scala复合类型解析:

  1. trait Compound_Type1;
  2. trait Compound_Type2;
  3. class Compound_Type extends Compound_Type1 with Compound_Type2
  4. object Compound_Type {
  5. def compound_Type(x: Compound_Type1 with Compound_Type2) = {println("Compound Type in global method")} //限制参数x即是Type1的类型,也是Type2的类型
  6. def main(args: Array[String]) {
  7. compound_Type(new Compound_Type1 with Compound_Type2) //匿名方式,结果:Compound Type in global method
  8. object compound_Type_oject extends Compound_Type1 with Compound_Type2 //object继承方式,trait混入object对象中
  9. compound_Type(compound_Type_oject) //结果都一样,Compound Type in global method
  10. type compound_Type_Alias = Compound_Type1 with Compound_Type2 //定义一个type别名
  11. def compound_Type_Local(x:compound_Type_Alias) = println("Compound Type in local method") //使用type别名进行限制
  12. val compound_Type_Class = new Compound_Type
  13. compound_Type_Local(compound_Type_Class) //结果:Compound Type in local method
  14. type Scala = Compound_Type1 with Compound_Type2 { def init():Unit } //type别名限制即是Type1,也是Type2,同时还要实现init方法
  15. }
  16. }
复制代码
Infix Type

Infix Type:中值类型,允许带有两个参数的类型。

  1. object Infix_Types {
  2. def main(args: Array[String]) {
  3. object Log { def >>:(data:String):Log.type = { println(data); Log } }
  4. "Hadoop" >>: "Spark" >>: Log //右结合,先打印出Spark,再打印出Hadoop
  5. val list = List()
  6. val newList = "A" :: "B" :: list //中值表达式
  7. println(newList)
  8. class Infix_Type[A,B] //中值类型是带有两个类型参数的类型
  9. val infix: Int Infix_Type String = null //此时A是Int,B为String,具体类型名写在两个类型中间
  10. val infix1: Infix_Type[Int, String] = null //和这种方式等价
  11. case class Cons(first:String,second:String) //中值类型
  12. val case_class = Cons("one", "two")
  13. case_class match { case "one" Cons "two" => println("Spark!!!") } //unapply
  14. }
  15. }
复制代码
self-type
  1. class Self {
  2. self => //self是this别名
  3. val tmp="Scala"
  4. def foo = self.tmp + this.tmp
  5. }
  6. trait S1
  7. class S2 { this:S1 => } //限定:实例化S2时,必须混入S1类型
  8. class S3 extends S2 with S1
  9. class s4 {this:{def init():Unit} =>} //也能用于结构类型限定
  10. trait T { this:S1 => } //也能用于trait
  11. object S4 extends T with S1
  12. object Self_Types {
  13. def main(args: Array[String]) {
  14. class Outer { outer =>
  15. val v1 = "Spark"
  16. class Inner {
  17. println(outer.v1) //使用外部类的属性
  18. }
  19. }
  20. val c = new S2 with S1 //实例化S2时必须混入S1类型
  21. }
  22. }
复制代码
  1. ---
  2. 关于作者: 陈光剑,江苏东海人, 号行走江湖一剑客,字之剑。程序员,诗人, 作家
  3. http://universsky.github.io/?
  4. ---
  5. <link rel="stylesheet" href="http://yandex.st/highlightjs/6.2/styles/googlecode.min.css">
  6. <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
  7. <script src="http://yandex.st/highlightjs/6.2/highlight.min.js"></script>
  8. <script>hljs.initHighlightingOnLoad();</script>
  9. <script type="text/javascript">
  10. $(document).ready(function(){
  11. $("h2,h3,h4,h5,h6").each(function(i,item){
  12. var tag = $(item).get(0).localName;
  13. $(item).attr("id","wow"+i);
  14. $("#category").append('<a class="new'+tag+'" href="#wow'+i+'">'+$(this).text()+'</a></br>');
  15. $(".newh2").css("margin-left",0);
  16. $(".newh3").css("margin-left",20);
  17. $(".newh4").css("margin-left",40);
  18. $(".newh5").css("margin-left",60);
  19. $(".newh6").css("margin-left",80);
  20. });
  21. });
  22. </script>
复制代码

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-6 21:44

Copyright 2015-2025 djqfx

返回顶部