摘要:函数式编程与面向对象编程的类型关联之剑目录类型关联关键字里的类型,除了在定义时会产生类型,还可以通过关键字来声明类型。复合类型与关键字这种形式的类型称为复合类型或者也叫交集类型。
函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
之剑 2016.5.4 23:55:19
scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型。
type相当于声明一个类型别名:
object TestMatrix extends App{ type IntList = List[Int] //接下来就可以这样使用它: type Matrix = List[IntList] val m = Matrix( IntList(1,2,3), IntList(1,2,3), IntList(1,2,3)) }
scala> type IntList=List[Int] defined type alias IntList
这种给类型一个别名的特性只是一个小糖豆,不太甜,真正有趣的是给一类操作命名(联想C#中定义delegate)。
比如这样:
type PersonPredicate = Person => Boolean
接受一个Person,返回一个Boolean,我们把这一类用来判断一个人是否符合某个条件的操作统称为PersonPredicate。
然后我们可以定义以下predicate:
val teenagerPred: PersonPredicate = person => person.age < 20
然后前面写过的teenagers方法就可以这样重新定义:
def teenagers(people: People): People = { people.filter(teenagerPred) }
按照这个思路下去,我们就可以开始composite functions了。比如说,我们跟人收税,就可以这么做:
type Tax = Person => Double val incomeTax: Tax = person => person.income * 5 / 100 val kejuanzaTax: Tax = person => person.income * 20 / 100 def giveMeYourMoney(p: Person) = { calculateTax(p, List(incomeTax, kejuanzaTax)) } def calculateTax(person: Person, taxes: List[Tax]): Double = { taxes.foldLeft(0d) { (acc, curTax) => acc + curTax(person) } }
总结一下type alia这个糖衣:
一个类型的type alias,类似于这样的:type t = x。编译器将在所有使用到t的地方把t替换为x。
对于一种操作的type alias,编译器将会根据参数列表和返回值类型的不同将其替换为对应的Function0,Function1,Function2 …… 一直到Function22。
如果我们真的定义一个超过22个参数的操作会如何呢?
type twentyThree = ( String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String ) => String
Scala编译器会直接告诉我们: type Function23 is not a member of package scala
结构类型结构类型(structural type)为静态语言增加了部分动态特性,使得参数类型不再拘泥于某个已命名的类型,只要参数中包含结构中声明的方法或值即可。举例来说,java里对所有定义了close方法的抽象了一个Closable接口,然后再用Closable类型约束参数,而scala里可以不要求参数必须继承自Closable接口只需要包含close方法;如下:
scala> def free( res: {def close():Unit} ) { res.close } scala> free(new { def close()=println("closed") }) closed
也可以通过type在定义类型时,将其声明为结构类型
scala> type X = { def close():Unit } defined type alias X scala> def free(res:X) = res.close scala> free(new { def close()=println("closed") }) closed
上面传入参数时,都是传入一个实现close方法的匿名类,如果某个类/单例中实现了close方法,也可以直接传入
scala> object A { def close() {println("A closed")} } scala> free(A) A closed scala> class R { def close()=print("ok") } scala> val r = new R scala> free(r) ok
结构类型还可以用在稍微复杂一点的“复合类型”中,比如:
scala> trait X1; trait X2; scala> def test(x: X1 with X2 { def close():Unit } ) = x.close
上面声明test方法参数的类型为:
X1 with X2 { def close():Unit }
表示参数需要符合特质X1和X2同时也要有定义close方法。
复合类型与with关键字class A extends (B with C with D with E) T1 with T2 with T3 …
这种形式的类型称为复合类型(compound type)或者也叫交集类型(intersection type)。
跟结构类型类似,可以在一个方法里声明类型参数时使用复合类型:
scala> trait X1; trait X2; scala> def test(x: X1 with X2) = {println("ok")} test: (x: X1 with X2)Unit scala> test(new X1 with X2) ok scala> object A extends X1 with X2 scala> test(A) ok
也可以通过 type 声明:
scala> type X = X1 with X2 defined type alias X scala> def test(x:X) = println("OK") test: (x: X)Unit scala> class A extends X1 with X2 scala> val a = new A scala> test(a) OK结构类型
结构类型:定义方法或者表达式时,要求传参具有某种行为,但又不想使用类,或者接口去限制,可以使用结构类型。
class Structural { def open()=print("A class instance Opened") } object Structural__Type { def main(args: Array[String]){ init(new { def open()=println("Opened") }) //创建了一个匿名对象,实现open方法 type X = { def open():Unit } //将右边的表达式命名为一个别名 def init(res:X) = res.open init(new { def open()=println("Opened again") }) object A { def open() {println("A single object Opened")} } //创建的单例对象里面也必须实现open方法 init(A) val structural = new Structural init(structural) } def init( res: {def open():Unit} ) { //要求传进来的res对象具有open方法,不限制类型 res.open } }
Scala复合类型解析:
trait Compound_Type1; trait Compound_Type2; class Compound_Type extends Compound_Type1 with Compound_Type2 object Compound_Type { def compound_Type(x: Compound_Type1 with Compound_Type2) = {println("Compound Type in global method")} //限制参数x即是Type1的类型,也是Type2的类型 def main(args: Array[String]) { compound_Type(new Compound_Type1 with Compound_Type2) //匿名方式,结果:Compound Type in global method object compound_Type_oject extends Compound_Type1 with Compound_Type2 //object继承方式,trait混入object对象中 compound_Type(compound_Type_oject) //结果都一样,Compound Type in global method type compound_Type_Alias = Compound_Type1 with Compound_Type2 //定义一个type别名 def compound_Type_Local(x:compound_Type_Alias) = println("Compound Type in local method") //使用type别名进行限制 val compound_Type_Class = new Compound_Type compound_Type_Local(compound_Type_Class) //结果:Compound Type in local method type Scala = Compound_Type1 with Compound_Type2 { def init():Unit } //type别名限制即是Type1,也是Type2,同时还要实现init方法 } }Infix Type
Infix Type:中值类型,允许带有两个参数的类型。
object Infix_Types { def main(args: Array[String]) { object Log { def >>:(data:String):Log.type = { println(data); Log } } "Hadoop" >>: "Spark" >>: Log //右结合,先打印出Spark,再打印出Hadoop val list = List() val newList = "A" :: "B" :: list //中值表达式 println(newList) class Infix_Type[A,B] //中值类型是带有两个类型参数的类型 val infix: Int Infix_Type String = null //此时A是Int,B为String,具体类型名写在两个类型中间 val infix1: Infix_Type[Int, String] = null //和这种方式等价 case class Cons(first:String,second:String) //中值类型 val case_class = Cons("one", "two") case_class match { case "one" Cons "two" => println("Spark!!!") } //unapply } }self-type
class Self { self => //self是this别名 val tmp="Scala" def foo = self.tmp + this.tmp } trait S1 class S2 { this:S1 => } //限定:实例化S2时,必须混入S1类型 class S3 extends S2 with S1 class s4 {this:{def init():Unit} =>} //也能用于结构类型限定 trait T { this:S1 => } //也能用于trait object S4 extends T with S1 object Self_Types { def main(args: Array[String]) { class Outer { outer => val v1 = "Spark" class Inner { println(outer.v1) //使用外部类的属性 } } val c = new S2 with S1 //实例化S2时必须混入S1类型 } }
--- 关于作者: 陈光剑,江苏东海人, 号行走江湖一剑客,字之剑。程序员,诗人, 作家 http://universsky.github.io/ ---
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/65874.html
摘要:第一节函数式范式什么是函数式编程函数式编程英语或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。 第一节 函数式范式 1. 什么是函数式编程 函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对...
摘要:函数式编程与面向对象编程表达式函数柯里化高阶函数之剑什么是表达式例子定义表达式是一个匿名函数,表达式基于数学中的演算得名,直接对应于其中的抽象,是一个匿名函数,即没有函数名的函数。 函数式编程与面向对象编程[1]: Lambda表达式 函数柯里化 高阶函数.md 之剑 2016.5.2 11:19:09 什么是lambda表达式 例子 For example, in Lisp the...
摘要:动态类型语言的表达力动态语言通常更方便开发较小的项目,因为可以无需声明类型而节省了很多麻烦。 函数式编程与面向对象编程[2]: 静态类型语言的表达力 静态类型语言与动态类型语言 之剑 2016.5.3 21:43:20 像Java或者C#这样强类型的准静态语言在实现复杂的业务逻辑、开发大型商业系统、以及那些生命周期很长的应用中也有着非常强的优势 下面我们就来学习一下这些知识. 有三...
摘要:我们的目标是建立对每一种语言的认识,它们是如何进化的,未来将走向何方。有点的味道是坚持使用动态类型,但唯一还收到合理拥泵的编程语言,然而一些在企业的大型团队中工作的开发者择认为这会是的一个缺陷。 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目。尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的JVM语言么? 如今借助来自...
摘要:入门,第一个这是一门很新的语言,年前后正式公布,算起来是比较年轻的编程语言了,更重要的是它是面向程序员的函数式编程语言,它的代码运行在之上。它通过编辑类工具,带来了先进的编辑体验,增强了语言服务。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不觉已经到来了,总结过去的 2017,相信小伙们一定有很多收获...
阅读 3078·2023-04-26 00:53
阅读 3525·2021-11-19 09:58
阅读 1695·2021-09-29 09:35
阅读 3281·2021-09-28 09:46
阅读 3857·2021-09-22 15:38
阅读 2695·2019-08-30 15:55
阅读 3009·2019-08-23 14:10
阅读 3823·2019-08-22 18:17