2012-01-12 43 views
10

Đoạn mã sau được lấy từ Lập trình trong sách Scala của Martin Odersky et al. xác định một loại hợp lý:Có thể định nghĩa biến hàm dựng trong Scala không?

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) 
} 

Ở đây giá trị g chỉ được sử dụng khi hàm tạo ngầm ngầm khởi tạo trường số và denom. Giả sử người lập trình biết rằng nó sẽ không được sử dụng ở bất cứ nơi nào khác. Trong trường hợp trên, nó vẫn có thể truy cập được sau khi xây dựng đối tượng Rational. Điều đó có nghĩa là nó cũng sẽ chiếm không gian kể từ khi là một trường riêng thay vì là một biến cục bộ cho hàm tạo.

Câu hỏi của tôi là làm cách nào để thay đổi mã này để g chỉ được sử dụng khi xây dựng và sau đó bị vứt bỏ?

+2

Đây là một trong những "điểm nóng" trong Scala. Hãy tưởng tượng rằng nếu đối tượng constructor đã cho chỉ được sử dụng để trích xuất một số thông tin tùy ý: có nó xung quanh mãi mãi sẽ giữ cho nó không đủ điều kiện để cải tạo ngay cả khi chỉ cần một nhóm nhỏ thông tin. Tôi nghĩ rằng có một cú pháp "cơ thể trước lớp", nhưng tôi không thể nhớ nó là gì. –

+0

@pst Cảm ơn bạn đã chỉnh sửa nhanh trong thời gian này. Của bạn trông tốt hơn mặc dù. :) – ciuncan

+2

Nếu có ai có bất kỳ liên kết nào liên quan đến cú pháp "tiền thân lớp" này, đề cập đến pst, tôi muốn được nghe về nó. –

Trả lời

10

Trong trường hợp này, làm thế nào về điều này?

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) 
} 

EDIT: này cũng tạo ra một trường bổ sung chứa một tuple, như thể hiện bằng cách chạy javap trên lớp biên soạn (nhờ, Alexey):

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); 
} 

Trong các trường hợp khác, đôi khi tôi sử dụng khối locally để tránh biến mỗi val vào một trường:

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

Cảm ơn bạn đây có thể là giải pháp tốt nhất. Tôi cũng đã học về khối "cục bộ", vì vậy cảm ơn một lần nữa. – ciuncan

+0

Tôi cũng có thể sử dụng các giá trị hoặc các biến được xác định trong khối cục bộ bên ngoài nó, chỉ trong phần thân của lớp đó không? Hoặc họ chỉ là địa phương để chặn địa phương? – ciuncan

+2

@ciuncan Mọi thứ được khai báo trong một khối mã (tức là được phân cách bằng dấu ngoặc nhọn) chỉ có thể truy cập được trong khối đó. 'cục bộ' chỉ là một phương pháp thuận tiện để tránh các vấn đề suy luận dấu chấm phẩy (không phải từ khóa), vì vậy không thể thay đổi điều này. Xem http://stackoverflow.com/questions/3237727/what-does-predef-locally-do-and-how-is-it-different-from-predef-identity để biết thông tin về 'cục bộ'. –

Các vấn đề liên quan