【正文】
ions have been defined for rational numbers. These are the canonical, mathematical operations add, subtract, multiply, and divide. Each of these is named by its mathematical symbol: +, , *, and /. Notice, however, that each of these operators works by constructing a new Rational object each time. Again, this is very similar to how works, and it is the default implementation because it yields threadsafe code. (If no shared state and internal state of an object shared across threads is implicitly shared state is modified by a thread, then there is no concern over concurrent access to that state.) What39。 but this assumption is incorrect. Formally, Scala calls numer and denom methods without parameters, which are used to create a quickandeasy syntax for defining accessors. The Rational class still has three private fields, n, d, and g, but they are hidden from the world by default private access in the case of n and d, and by explicit private access in the case of g. The Java programmer in you is probably asking at this point, Where are the corresponding setters for n and d? No such setters exist. Part of the power of Scala is that it encourages developers to create immutable objects by default. Granted, syntax is available to create methods for modifying the internals of Rational, but doing so would ruin the implicit threadsafe nature of this class. As a result, at least for this example, I39。s constructor chain does the usual Javaconstructorchaining thing by calling into the preferred constructor (the Int,Int version). Details, (implementation) details... When working with rational numbers, it helps to perform a bit of numerical legerdemain: namely that of finding a mon denominator to make certain operations easier. If you want to add 1over2 (also known as onehalf) to 2over4 (also known as twofourths), the Rational class should be smart enough to realize that 2over4 is the same as 1over2, and convert it accordingly before adding the two together. 4 This is the purpose of the nested private gcd() function and g value inside of the Rational class. When the constructor is invoked in Scala, the entire body of the class is evaluated, which means g will be initialized with the greatest mon denominator of n and d, and then used in turn to set n and d appropriately. Looking back at Listing 1, it39。s default constructor class Rational(n:Int, d:Int) { // ... Although you might think you39。ll point it out. Scala has class(es), too Rather than embark on a lengthy and abstract discussion of the class features that Scala supports, let39。s functional programming features are pelling, but they39。ll see some interesting tidbits related to class definitions and usage in Scala. In last month39。 1 來自: think in java ( 3) 外文原文 The busy Java developer39。s article , you saw just a touch of Scala39。re not the only reason Java developers should be interested in the language. In fact, Scala blends functional concepts and object orientation. In order to let the JavacumScala programmer feel more at home, it makes sense to look at Scala39。s look at a definition for a class that might be used to bring rational number support to the Scala platform (largely swiped from Scala By Example see Resources): Listing 1. class Rational(n:Int, d:Int) { private def gcd(x:Int, y:Int): Int = { if (x==0) y else if (x0) gcd(x, y) else if (y0) gcd(x, y) 2 else gcd(y%x, x) } private val g = gcd(n,d) val numer:Int = n/g val denom:Int = d/g def +(that:Rational) = new Rational(numer* + *denom, denom * ) def (that:Rational) = new Rational(numer * * denom, denom * ) def *(that:Rational) = new Rational(numer * , denom * ) def /(that:Rational) = new Rational(numer * , denom * ) override def toString() = Rational: [ + numer + / + denom + ] } While the overall structure of Listing 1 is lexically similar to what you39。re looking at some kind of genericslike syntax in Listing 3, it39。s also fairly easy to see that I created an overridden toString method to return the values of Rational, which will be very useful when I start exercising it from the RunRational driver code. Notice the syntax around toString, however: the override keyword in the front of the definition is required so that Scala can check to make sure that a corresponding definition exists in the base class. This can help prevent subtle bugs created by accidental keyboard slips. (It was this same motivation that led to the creation of the Override annotation in Java 5.) Notice, as well, that the return type is not specified it39。m going to leave Rational as it is. Naturally, that raises the question of how one manipulates a Rational. Like , you can39。s new with you? The everything is a function rule has two powerful effects: The first, as you39。s purely a syntactic nit: Listing 6. This is how you flip class Rational(n:Int, d:Int) { 6 // ... as before ... def unary_~ : Rational = new Rational(denom, numer) } The tricky part is, of course, the fact that you have to prefix the ~ name with unary_ to tell the Scala piler that it is intended to be a unary operator。 private int numer。 public toString()。 public Rational $plus(Rational)。 private int gcd(int, int)。 thus far, I have been lax in exercising this rule for my Scala code, so let?s see what 8 happens when you put this Rational class inside of a traditional JUnit test suite, as shown in Listing 10: Listing 10. import .*。 assertTrue(() == 5)。 // 1 because of gcd() invocation during construction。 //r1.$plus(r2)。s used in nested and anonymous nested class names). In order to invoke those methods, you e