2012-01-12 186 views
10

以下代码来自Martin Odersky等人编写的Scala书籍。它定义了一个合理的类型:是否有可能在Scala中定义构造函数局部变量?

class Rational(n: Int, d: Int) { 
    require(d != 0) 
    private val g = gcd(n.abs, d.abs) 
    val numer = n/g 
    val denom = d/g 
    ... 
    private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) 
} 

这里的值g只在隐式构造函数初始化字段numer和denom时使用。假设程序员知道它不会在其他地方使用。在上述情况下,在构造Rational对象之后仍然可以访问它。这意味着它将占用空间,因为它是一个私有字段,而不是构造函数的局部变量。

我的问题是如何更改此代码,以便g仅在施工时使用,然后丢弃?

+2

这是Scala中那些“恶心点”之一。想象一下,如果给定的构造函数对象仅用于提取一些任意的信息:即使只需要一小部分信息,永久使用它也会使其不适合回收。我认为有一个“课前体”的语法,但我不记得它是什么。 – 2012-01-12 22:15:40

+0

@pst感谢您的快速编辑,我在此期间正在这么做。你的看起来好多了。 :) – ciuncan 2012-01-12 22:16:20

+2

如果任何人有任何关于pst提到的“pre-class body”语法的链接,我很乐意听到它。 – 2012-01-13 01:16:30

回答

10

在这种情况下,这样的事情呢?

class Rational(n: Int, d: Int) { 
    require(d != 0) 
    val (numer, denom) = { 
    val g = gcd(n.abs, d.abs) 
    (n/g, d/g) 
    } 
    private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) 
} 

编辑:这也创建了拥有一个元组,如通过在编译的类(感谢,阿列克谢)运行javap一个额外的字段:

public class Rational extends java.lang.Object implements scala.ScalaObject{ 
    private final scala.Tuple2 x$1; // actually unwanted! 
    private final int numer; 
    private final int denom; 
    public int numer(); 
    public int denom(); 
    private int gcd(int, int); 
    public Rational(int, int); 
} 

在其他情况下,我有时使用locally块来避免每个val转化为一个字段:

class A { 
    locally { 
    val value1 = // ... 
    val value2 = // ... 
    } 
} 
+0

谢谢你可能是最好的解决方案。我还了解了“本地”区块,所以再次感谢。 – ciuncan 2012-01-12 22:31:20

+0

我是否也可以使用在本地块外定义的值或变量,就在该类体中?或者他们只是本地阻止? – ciuncan 2012-01-12 22:35:13

+2

@ciuncan在代码块中声明的任何内容(即用大括号分隔)只能在该块内访问。 “本地”仅仅是避免分号推理问题(不是关键字)的一种便利方法,所以不能改变它。有关'本地“的信息,请参阅http://stackoverflow.com/questions/3237727/what-does-predef-locally-do-and-how-is-it-different-from-predef-identity。 – 2012-01-13 01:11:44

相关问题