加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala编译器对类型系统中的单元类型有什么特殊规则

发布时间:2020-12-16 09:44:59 所属栏目:安全 来源:网络整理
导读:该单元在生成字节代码时由编译器进行特殊处理,因为它类似于jvm上的void。但在概念上作为Scala类型系统中的一种类型,它似乎也在语言本身得到特殊的处理(下面的例子)。 所以我的问题是澄清这一点,了解什么机制被使用,如果真的有特殊待遇的单位类型。 实施
该单元在生成字节代码时由编译器进行特殊处理,因为它类似于jvm上的void。但在概念上作为Scala类型系统中的一种类型,它似乎也在语言本身得到特殊的处理(下面的例子)。

所以我的问题是澄清这一点,了解什么机制被使用,如果真的有特殊待遇的单位类型。

实施例1:

对于“常规”Scala类型,如Seq,如果方法返回Seq,则必须返回Seq(或扩展Seq的更具体类型)

def foo1: Seq[Int] = List(1,2,3)
def foo2: Seq[Int] = Vector(1,3)
def foo3: Seq[Int] = "foo" // Fails

前两个示例编译,因为List [Int]和Vector [Int]是Seq [Int]的子类型。第三个失败,因为String不是。

但是如果我更改了第三个例子来返回Unit,那么即使String不是Unit的子类型,它也会编译并运行,

def foo3(): Unit = "foo" // Compiles (with a warning)

我不知道在scala中允许这个例外的任何其他类型。那么编译器在类型系统级别对于Unit类型有特殊规则,还是在工作中有某种更通用的机制。隐式转换。

实施例2:

在通常应用差异规则的情况下,我也不清楚单位如何相互作用。

例如,我们有时会与Future [Unit]碰到这个错误,我们不小心使用map而不是flatMap并创造未来[未来]:

def save(customer: Customer): Future[Unit] = ... // Save to database

def foo: Future[Unit] = save(customer1).map(_ => save(customer2))

该地图正在创造未来[未来[单位]],编译器需要未来[单位]。然而这个编译!

起初我以为这是因为未来[T]是协变的,但实际上未来[Unit]不是Unit的子类型,所以似乎不是这样的。

例如,如果类型更改为布尔值,则编译器会检测到该错误:

def save(customer: Customer): Future[Boolean] = ...

def foo: Future[Boolean] = save(customer1).map(_ => save(customer2)) // Compiler fails this

而对于其他非单元类型,它不会编译(除了Any,因为Future [Any]恰好是偶的子类型)。

在这种情况下,编译器是否有特殊规则?还是有更一般的过程发生?

解决方法

我要回答标题问题以获得更多的报道。单位在几个地方得到特别待遇,超过了这些代码示例的发展。在某种程度上,这是因为Unit是一个在JVM上减少到void的编译器的图形。

价值放弃

这对人们来说是最令人惊讶的例子。任何时候,某些值的预期类型为Unit,编译器将根据产生该值的表达式结尾处的Unit单位,根据SLS – 6.26.1:

If ee has some value type and the expected type is Unit,ee is converted to the expected type by embedding it in the term { ee; () }.

从而,

def foo3(): Unit = "foo"

变为:

def foo3(): Unit = { "foo" ; () }

同样地,

def foo: Future[Unit] = save(customer1).map(_ => save(customer2))

变为:

def foo: Future[Unit] = save(customer1).map(_ => { save(customer2); () })

这样做的好处是,如果您不想,则不需要具有类型Unit的方法的最后一个语句。但是,这个优点很小,因为如果返回Unit的方法的最后一个语句不是Unit,那通常会指示一个错误,这就是为什么它有一个警告标志(-Ywarn-value-discard)。

一般来说,如果可能的话,我更好地返回一个更具体的类型,而不是返回Unit。例如,保存到数据库时,您可以返回保存的值(可能使用新的ID或某些东西)。

价值类

单位是由Scala编译器创建的值类,只有一个实例(如果需要被实例化为一个类)。这意味着它可以编译为JVM上的原始void,除非将它视为一个类(例如().toString)。它在规范SLS – 12.2.13中有自己的一部分。

空块类型

从SLS – 6.11开始,空块的默认类型为Unit。例如:

scala> val x = { }
x: Unit = ()

等于

当将一个单元与另一个单元(必须是相同的对象,因为只有一个)相比较时,编译器会发出一个特殊的警告来通知你的程序可能有错误。

scala> ().==(())
<console>:12: warning: comparing values of types Unit and Unit using `==' will always yield true
       ().==(())
            ^
res2: Boolean = true

铸件

您可以将任何内容投放到单元,因为编译器会将其优化(尽管如果在丢弃类型推断后丢弃值丢弃,我们不清楚)。

object Test {
  val a = "a".asInstanceOf[Unit]
  val b = a
}

变为:

object Test extends Object {
  def <init>(): Test.type = {
    Test.super.<init>();
    ()
  };
  private[this] val a: scala.runtime.BoxedUnit = scala.runtime.BoxedUnit.UNIT;
  <stable> <accessor> def a(): Unit = ();
  private[this] val b: scala.runtime.BoxedUnit = scala.runtime.BoxedUnit.UNIT;
  <stable> <accessor> def b(): Unit = ()
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读