2012-01-12 181 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

相關問題