前向引用-为什么要编译此代码? [英] Forward References - why does this code compile?

查看:58
本文介绍了前向引用-为什么要编译此代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码段:

 object A {
     val b = c
     val c = "foo"
 }
 println( A.b )   // prints "null"

作为较大程序的一部分,这将导致运行时失败.显然,编译器允许从"b"到(未初始化的)"c"的前向引用,但"b"保留了c的原始空值.为什么允许这样做?是否有可以从该功能中受益的编程方案?

As part of a larger program, this would lead to a failure at runtime. The compiler apparently permits the forward reference from 'b' to (uninitialized) 'c' but 'b' is left with c's original null value. Why is this permitted? Are there programming scenarios that would benefit from this feature?

将代码更改为直线序列,行为将更改:

Change the code to a straight sequence and the behavior changes:

 val b = c
 val c = "foo"
 println( b )   // prints "foo"

为什么行为不同?为何这还行得通呢?谢谢.

Why is the behavior different? And why does this even work? Thanks.

更新1:

问题来了,我如何运行第二个示例.我稍微简化了设置,并在IntelliJ IDEA 10.5.2中使用Scala 2.9.0.1和最新的Scala插件对其进行了编译.这是一个新创建的,否则为空的项目中的确切代码,我正在使用它来对其进行测试,该代码可以在此环境中编译并正常运行:

The question came up how I ran the second example. I simplified the setup a bit and compiled it using Scala 2.9.0.1 inside IntelliJ IDEA 10.5.2 with the latest Scala plugin. Here is the exact code, in a freshly created and otherwise empty project, which I am using to test this, which compiles and runs fine in this environment:

 package test
 object Main { 
    def main( args: Array[String] ) {
       val b = c
       val c = "foo"
       println( b )   // prints "foo"
    }
 }

对于它的价值,IDEA还认为(当我单击通过" val b = c中对"c"的引用时)时,我指的是"c"的(以后)声明.

For what it's worth, IDEA also thinks (when I click "through" the reference to 'c' in val b = c) that I am referring to the (later) declaration of 'c'.

推荐答案

类或对象的主体是主要的构造方法.构造器与方法一样,是按顺序执行的语句序列-要执行其他任何操作,它必须是一种完全不同的语言.我敢肯定,您不希望Scala以除顺序之外的任何其他顺序执行方法的语句.

The body of a class or an object is the primary constructor. A constructor, like a method, is a sequence of statements that are executed in order -- to do anything else, it would have to be a very different language. I'm pretty sure you wouldn't like for Scala to execute the statements of your methods in any other order than sequential.

这里的问题是类和对象的主体也是成员的声明,这是造成混淆的原因.您可以精确地看到val声明:一种声明性的编程形式,例如Prolog程序或XML配置文件.但是它们实际上是两件事:

The problem here is that the body of classes and objects are also the declaration of members, and this is the source of your confusion. You see val declarations as being precisely that: a declarative form of programming, like a Prolog program or an XML configuration file. But they are really two things:

// This is the declarative part
object A {
  val b
  val c
}

// This is the constructor part
object A {
  b = c
  c = "foo"
}

问题的另一部分是您的示例非常简单.在特殊情况下,某种行为似乎是有道理的.但是请考虑以下内容:

Another part of your problem is that your example is very simple. It is a special case in which a certain behavior seems to make sense. But consider something like:

abstract class A {
  def c: String
}

class B extends A {
  val b = c
  override val c = "foo"
}

class C extends { override val c = "foobar" } with B

val x = new C
println(x.b)
println(x.c)

您期望发生什么?构造函数执行的语义保证了两件事:

What do you expect to happen? The semantics of constructor execution guarantees two things:

  1. 可预测性.您一开始可能会觉得它不直观,但是规则很明确并且相对容易遵循.
  2. 子类可以依赖于已初始化自身的超类(因此,可以使用其方法).

输出:

它将两次多次打印"foobar" => https: //docs.scala-lang.org/tutorials/FAQ/initialization-order.html

it will print "foobar" twice for more => https://docs.scala-lang.org/tutorials/FAQ/initialization-order.html

这篇关于前向引用-为什么要编译此代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆