scala类型系统:3) 单例类型与this.type

scala类型系统:3) 单例类型与this.type

对于单例类型(singleton type),在《scala impatient》这本书(中文版:快学scala)里有提到过,当时读的时候,扫了一下,以为就是指scala里用object定义的这种单例对象呢,没有仔细看,最近才发现其实singleton type 是所有实例都可以有

scala> object A

scala> A.getClass
res2: Class[_ <: A.type] = class A$

scala> typeOf[A.type]
res0: reflect.runtime.universe.Type = A.type

对于这种单例,它的类型与它的类不同,要用 A.type 来表示。
这有点怪,通常我们不会用它,比如下面的方式都多此一举:

scala> val a : A.type = A

scala> def foo() : A.type = A

一方面因为scala有类型推导的功能,另一方面,因为单例是唯一的,A.type类型只有唯一的实例A(排除null),我需要的话直接用A就好了。

不过我们讨论的话题重点是 singleton type,想象一下A是一个对象实例,是否对任何实例x都存在一个x.type这样的类型呢?

scala> class A

scala> val a = new A

scala> typeOf[a.type]
res0: reflect.runtime.universe.Type = a.type

wow,真的存在。再用这个类型声明一个变量看看:

scala> val x:a.type = a
x: a.type = A@6738694b

灵的,如果赋一个非a的实例呢?

scala> val x:a.type = a2
<console>:13: error: type mismatch;
     found   : a2.type (with underlying type A)
     required: a.type

scala> typeOf[a.type] == typeOf[A]  // a.type 与 A 不是同一个类型
res2: Boolean = false

scala> typeOf[a.type] == typeOf[a2.type] // a.type 与 a2.type 也不同
res1: Boolean = false

scala> typeOf[a.type] <:< typeOf[A] // a.type 是 A 类型的子类型
res5: Boolean = true

看到了,a.type 与 a2.type 是不同的类型!a.type也是单例类型,它也只有唯一的实例: a (排除null)

所有的对象实例都有一个x.type的单例类型,它只对应当前对象实例。这么做有什么意义呢?

这里看到一种情况,在“链式”调用风格下,有适用的场景:

class A {def method1: A = this }
class B extends A {def method2: B = this}

val b = new B
b.method2.method1  // 可以工作
b.method1.method2  // 不行,提示:error: value method2 is not a member of A

有些人很喜欢用 x.foo.bar 这样的方式连续的去操作,这种风格也成为”链式调用”风格,它要求方法返回的必须是当前对象类型,以便连贯的调用方法。不过上面,因为父类中声明的method1方法返回类型限制死了就是A类型(不写返回值类型,用类型推导也一样),导致子类对象调用完method1之后,类型已经变成了父类型,无法再调用子类型中的方法了。解决方法是:

class A { def method1: this.type = this } 
class B extends A { def method2 : this.type = this } 

val b = new B
b.method1.method2  // ok

把返回类型都改为了 this.type 单例类型,就灵了。它利用了this关键字的动态特性来实现的,在执行b.method1 的时候,method1返回值类型this.type 被翻译成了B.this.type

scala> b.method1
res0: b.type = B@ca5bdb6

这样不同的对象实例在执行该方法的时候,返回的类型也是不同的(都是当前实例的单例类型)。

小结,单例类型是个特殊的类型,单例类型绑定(依赖)在某个对象实例上,每个对象实例都有它的单例类型。不过它的场景并不多见。

转载自:http://hongjiang.info/scala/   推荐大家阅读下这位大哥出版的书《Scala函数式编程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchFieldException: DEFAULT_TINY_CACHE_SIZE at org.apache.spark.network.util.NettyUtils.getPrivateStaticField(NettyUtils.java:131) at org.apache.spark.network.util.NettyUtils.createPooledByteBufAllocator(NettyUtils.java:118) at org.apache.spark.network.server.TransportServer.init(TransportServer.java:95) at org.apache.spark.network.server.TransportServer.<init>(TransportServer.java:74) at org.apache.spark.network.TransportContext.createServer(TransportContext.java:114) at org.apache.spark.rpc.netty.NettyRpcEnv.startServer(NettyRpcEnv.scala:118) at org.apache.spark.rpc.netty.NettyRpcEnvFactory$$anonfun$4.apply(NettyRpcEnv.scala:454) at org.apache.spark.rpc.netty.NettyRpcEnvFactory$$anonfun$4.apply(NettyRpcEnv.scala:453) at org.apache.spark.util.Utils$$anonfun$startServiceOnPort$1.apply$mcVI$sp(Utils.scala:2237) at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:160) at org.apache.spark.util.Utils$.startServiceOnPort(Utils.scala:2229) at org.apache.spark.rpc.netty.NettyRpcEnvFactory.create(NettyRpcEnv.scala:458) at org.apache.spark.rpc.RpcEnv$.create(RpcEnv.scala:56) at org.apache.spark.SparkEnv$.create(SparkEnv.scala:246) at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:175) at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:257) at org.apache.spark.SparkContext.<init>(SparkContext.scala:432) at org.apache.spark.SparkContext$.getOrCreate(SparkContext.scala:2509) at org.apache.spark.sql.SparkSession$Builder$$anonfun$6.apply(SparkSession.scala:909) at org.apache.spark.sql.SparkSession$Builder$$anonfun$6.apply(SparkSession.scala:901) at scala.Option.getOrElse(Option.scala:121) at org.apache.spark.sql.SparkSession$Builder.getOrCreate(SparkSession.scala:901) at com.cssl.scala720.KafkaSparkStreamingHBase$.main(KafkaSparkStreamingHBase.scala:28) at com.cssl.scala720.KafkaSparkStreamingHBase.main(KafkaSparkStreamingHBase.scala) Caused by: java.lang.NoSuchFieldException: DEFAULT_TINY_CACHE_SIZE at java.lang.Class.getDeclaredField(Class.java:2070) at org.apache.spark.network.util.NettyUtils.getPrivateStaticField(NettyUtils.java:127) ... 23 more Process finished with exit code 1
07-24

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值