From Scala wizard Chapter 1 functional objects
With the basic Scala knowledge gained from the previous chapters, you are ready to explore how to design objects with more comprehensive features in Scala. This chapter focuses on defining functional objects, that is, classes of objects without any variable states. As an example of running, we will create several Class variants that use scores as immutable object modeling. In this process, we will show you more aspects of scala Object-Oriented Programming: Class parameters and constructors, methods and operators, Private Members, subclass method overloading, prerequisite checks, overload and self-pointing of similar methods.
1.1 rational style books
Score:Rational NumberIs a ratio that can be expressed as a ratio.NumberHere, the sum is a number, and it cannot be zero. CalledNumerator:Numerator, CalledDenominator:Denominator. Examples of scores include:, and. Compared with floating-point numbers, the fractional part is fully expressed without rounding or estimation.
In this chapter, we will design classes that must model scores, including allowing them to perform addition, subtraction, multiplication, and Division operations. To add two scores, you must first obtain the denominator before adding the two molecules. For example, to calculate the value, first multiply the upper and lower parts of the left operand by 3, and then the two parts of the right operand by 2. Add the two molecules to produce the result ,. To multiply two scores, simply multiply the two numerics and then multiply the two denominator. Therefore, we can also simplify the representation into its "normal" form. Division is to replace the right operand numerator denominator and then perform multiplication. For example, if it is the same, the result is.
One is probably not very important. The discovery is in mathematics,The score cannot be changed. When a score is added to another score, the result is a new score. The original number is not "changed ". The immutable rational class we will design in this chapter will adhere to this attribute.Each score is represented as a rational object. When two rational objects are added, a new rational object with accumulative results will be created..
This chapter also introduces some Scala methods for writing libraries that feel like native languages. For example, you can use the rational class at the end of this chapter:
Scala> Val onehalf = New Rational (1, 2)
Onehalf: Rational = 1/2
Scala> Val twothirds = New Rational (2, 3)
Twothirds: Rational = 2/3
Scala> (onehalf/7) + (1 twothirds)
Res0: Rational = 17/42
1.2 create rational
Starting to design the rational class is to consider the customerProgramHow Members will create a new rational object. Assuming that we have decided to make the rational object immutable, we will need the customer to provide all the required data (in this example, it is the numerator and denominator) when creating the instance ). Therefore, we should start designing like this:
Class rational (N: int, D: INT)
This lineCodeFirst, you should note that if the class has no subject, you do not need to specify an empty braces (if you want ). In the class name, rational, the N and D in the brackets are calledClass parameters:Class Parameter. The Scala compiler collects these two class parameters and createsMaster constructor:Primary Constructor.
Balance between immutable objects
Immutable objects provide several advantages over mutable objects and a potential disadvantage..FirstImmutable objects are often more logical than mutable objects because they do not have a complex state space that changes over time.Second, You can freely pass immutable objects, but you may need to build a copy just in case before passing a mutable object to other code.ThirdThere is no chance to let two threads that access an immutable object at the same time destroy its reasonably constructed state, because no thread can change the state of an immutable object at all.FourthThe unchangeable object makes the hash table key value safer. For example, if a variable object is changed after it is put into a hashset, you will not be able to find the hashset next time.
The only drawback of immutable objects is that they sometimes need to copy large object graphs, and the update of immutable objects can happen in the same place. In some cases, this will become difficult to complete quickly and may cause performance bottlenecks.. As a result, it is not uncommon for the database to provide a variable substitution to make it easier to change some elements in the middle of the big data structure. For example, the stringbuilder class is a mutable replacement of strings. In chapter 2, we will show more details about designing mutable objects in Scala.
Note:
The original rational example highlights the differences between Java and Scala.Java classes have constructors that can contain parameters, while Scala classes can directly contain parameters. Scala is more concise-class parameters can be directly used in the class bodyNo need to define the field and then write the value assignment function to copy the parameters of the constructor to the field. This can potentially save a lot of fixed writing, especially for small classes.
The Scala compiler will compile any code you put inside the class that is not a field or method definition into the main constructor.. For example, you can print an error message like this:
Class rational (N: int, D: INT ){
Println ("created" + N + "/" + D)
}
According to this Code, the scala compiler will place the println call in the rational master constructor. Therefore, the println call prints this debugging message every time a new rational instance is created:
Scala> New Rational (1, 2)
Created 1/2
Res0: Rational = rational @ a0b0f5
1.3 re-implement the tostring Method
When a rational instance is created in release, the interpreter prints "rational @ a0b0f5 ". The interpreter is a string that looks a little forward by calling the tostring method of the rational object. By default, the rational class inherits the tostring Implementation defined on the java. Lang. Object Class,Only print the class name, a @ symbol, and a hexadecimal number.. The result of tostring is mainly to provide help to programmers by providing the information output by the statement printing, log message, Test Error Report and interpreter and the debugger when the error is eliminated. Currently, the results provided by tostring are not particularly useful because it does not provide any clue about the rational value it is called. The more useful tostring implementation should print out the rational numerator and denominator.You can add the tostring Method to the rational class to overload the load:OverrideDefault implementationSuch:
Class rational (N: int, D: INT ){
Override def tostring = N + "/" + d
}
The override modifier before the method definition indicates that the previous method definition is overloaded.; Chapter 2 will further explain. Now the score is very beautiful, so we removed the println debugging statement in the rational class of the previous version. You can test the new behavior of rational in the interpreter:
Scala> Val x = New Rational (1, 3)
X: Rational = 1/3
Scala> Val y = New Rational (5, 7)
Y: Rational = 5/7
1.4 check prerequisites
Next, we will turn our eyes to some problems in the current main constructor behavior. As mentioned earlier in this chapter, the denominator of a score cannot be zero. However, at present, the main constructor will pass zero to D:
Scala> New Rational (5, 0)
Res6: Rational = 5/0
One advantage of object-oriented programming is that it allows you to encapsulate data in objects so that you can ensure that data is valid throughout the lifecycle.. Immutable objects like rational, which means you must ensure that the data is valid when the object is created (and ensure that the object is indeed immutable, in this way, the data will not become invalid later ). Since zero denominator is invalid for rational, it is imperative that rational cannot be built when zero is passed to D.
The best way to solve this problem isDefine a prerequisite for the master constructor:PreconditionIt indicates that D must be a non-zero value. A prerequisite is the restriction on the value passed to the method or constructor, which must be met by the caller.. One way is to use the require method. [1] For example:
Class rational (N: int, D: INT ){
Require (D! = 0)
Override def tostring = N + "/" + d
}
The require method carries a Boolean parameter. If the input value is true, require returns a normal result. Conversely, require will throw illegalargumentexception to prevent object construction.
1.5 Add a field
Now the main constructor can correctly execute the prerequisites and we will focus on supporting addition. To achieve this, we will define a public add method on the rational class, which carries another rational as the parameter. To keep the rational variable unchangeable, The add method must not add the passed scores to itself. Instead, you must create and return a brand new rational with accumulative values. You may want to write add as follows:
Class rational (N: int, D: INT) {// compiled
Require (D! = 0)
Override def tostring = N + "/" + d
Def add (that: Rational): Rational =
New Rational (N * That. d + that. N * D, D * That. d)
}
Unfortunately, the above Code prompts the compiler to say:
<Console>: 11: Error: value D is not a member of rational
New Rational (N * That. d + that. N * D, D * That. d)
Bytes
<Console>: 11: Error: value D is not a member of rational
New Rational (N * That. d + that. N * D, D * That. d)
Bytes
Although the class parameters n and D are within the scope that can be referenced by your Add code, they can only access their values in the objects that call add. Therefore, when you talk about N or D in the add implementation, the compiler will be happy to provide you with the values of these class parameters. But it will never let you use that. N or that. D, because that does not point to the rational object called by add. [2] to access N and D of that, you need to put them in the field. Code 6.1 demonstrates how to add these fields to the rational class. [3]
In the rational version shown in code 6.1, we added two fields, numer and denom, and initialized them with class parameters n and D. [4] We also changed the tostring and add implementations so that they can use fields instead of class parameters. This version of rational-like can be compiled and tested by adding scores:
Class rational (N: int, D: INT ){
Require (D! = 0)
Val numer: Int = N
Val denom: Int = d
Override def tostring = numer + "/" + denom
Def add (that: Rational): Rational =
New Rational (
Numer * That. denom + that. numer * denom,
Denom * That. denom
)
}
Code 6.1 field-specific rational
Scala> Val onehalf = New Rational (1, 2)
Onehalf: Rational = 1/2
Scala> Val twothirds = New Rational (2, 3)
Twothirds: Rational = 2/3
Scala> onehalf add twothirds
Res0: Rational = 7/6
Another thing that can't be done before is to access the numerator and denominator outside the object. You only need to access the common numer and denom fields:
Scala> Val r = New Rational (1, 2)
R: Rational = 1/2
Scala> r. numer
Res7: Int = 1
Scala> r. denom
Res8: Int = 2
1.6 self-directed
This keyword points to the object instance called by the current execution method, or if used in the constructor, it is the object instance being constructed.. For example, we want to add a method lessthan to test whether the given score is smaller than the input parameter:
Def lessthan (that: Rational) =
This. numer * That. denom <that. numer * This. denom
Here, this. numer points to the molecule of the object called by lessthan. You can also remove the This prefix and write numer. The two statements are the same.
For example, to add the max Method to the rational class to return the larger values of the specified score and parameter:
Def max (that: Rational) =
If (this. lessthan (that) that else this
Here, the first one is redundant, and the same is true for lessthan (that. But the second this indicates the result of the method when the test is false; if you omit it, nothing will be returned.
1.7 slave Constructor
Sometimes multiple constructors are required in a class.Constructors other than the main constructor in Scala are called slave constructor:Auxiliary Constructor. For example, the score with the denominator of 1 is more concise if only the numerator is written. For example, it can be written as 5. Therefore, if it is not written as rational (5, 1), it may be better for the customer programmer to simply write it as rational (5. In this case, you need to add a constructor with only one parameter, molecule, to rational and set the denominator to 1 in advance. Code 6.2 shows what it should look like.
Class rational (N: int, D: INT ){
Require (D! = 0)
Val numer: Int = N
Val denom: Int = d
Def this (N: INT) = This (n, 1)
Override def tostring = numer + "/" + denom
Def add (that: Rational): Rational =
New Rational (
Numer * That. denom + that. numer * denom,
Denom * That. denom
)
}
Code 6.2 rational with slave Constructor
Scala's constructor starts with Def this (...). The main body of the rational sub-constructor is almost completely calling the main constructor, directly passing its unique parameter, N, as the numerator and 1 as the denominator. Enter the following code to the interpreter to see the effect of the constructor:
Scala> Val y = New Rational (3)
Y: Rational = 3/1
The first action of each slave constructor in Scala is to call other constructor in the same class. In other words, each slave constructor in each Scala class begins with "This (...)". The called constructor can be a master Constructor (like the rational example), or other constructor that is earlier than the called constructor in the text. The fundamental result of this rule is that each Scala constructor call will end with the call to the main constructor of the class. Therefore, the main constructor is the unique entry point of the class.
Note:
If you are familiar with Java, you may wonder why Scala constructor rules are bigger than Java. In Java, the first action of the constructor must either call another constructor of the same type or directly call the constructor of the super class. In Scala, only the main constructor can call the constructor of the superclass. The stricter restrictions in Scala are actually the designs made after balancing the higher conciseness and the cost of simplicity compared to the Java constructor. The details of the superclass, constructor call and inheritance interaction are described in Chapter 10th.
1.8 private fields and Methods
In the previous version of rational, We initialized numer with N and denom with d respectively. As a result, the numerator and denominator of rational may be larger than what it needs. For example, scores can be simplified to the same simplest form, but the rational master constructor does not do this currently:
Scala> New Rational (66, 42)
Res15: Rational = 66/42
To simplify the score, divide the numerator and denominatorMaximum common approx:Greatest Common Divisor. For example, the maximum common divisor of 66 and 42 is 6. (6 is the maximum integer between 66 and 42 .) The simplest form of the numerator and denominator generated by dividing by 6 ,. Code 6.3 demonstrates how to do this:
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
Def this (N: INT) = This (n, 1)
Def add (that: Rational): Rational =
New Rational (
Numer * That. denom + that. numer * denom,
Denom * That. denom
)
Override def tostring = numer + "/" + denom
Private def gcd (A: int, B: INT): Int =
If (B = 0) A else gcd (B, A % B)
}
Code 6.3 rational with private fields and Methods
In this version of rational, we added the private field, G, and modified the numer and denom initiators (initializer is the initialization variable, for example, initialize the "N/g" code of numer ). Because G is private, it can only be within the class body, but cannot be accessed outside. We also added a private method, gcd, which is used to calculate the maximum common number of Two incoming int values. For example, gcd (12, 8) is 4. As you can see in section 4.1, to privatize a field or method, you only need to put the private keyword before the definition. The private "helper method" GCD aims to separate the other parts of the class, which is the main constructor and requires code. To ensure that G is always positive, we pass in the absolute values of N and D and call ABS to obtain the absolute values of any integer.
The Scala compiler will initialize the three fields of rational according to theirSource codeIn the main constructor. Therefore, the G initialization code, gcd (N. Abs, D. Abs), will be executed before the other two because it appears in the source file as early as possible. G will be initialized as the maximum common divisor of the absolute values of class parameters, N and D. It is then used for numer and denom initialization. By dividing N and d by their maximum common divisor, G, each rational will be constructed into its simplest form:
Scala> New Rational (66, 42)
Res24: Rational = 11/7
1.9 define Operators
The current implementation of rational addition is no problem in terms of function completion only, but it can be better used. You may ask yourself why you can write an integer or floating point number as follows:
X + Y
However, if it is a score, it must be written as follows:
X. Add (y)
Or at least:
X Add y
There is no reasonable explanation. The score should be the same as other numbers. From a mathematical perspective, they are even more natural than floating point numbers. Why can't we use natural mathematical operators? You can do this in Scala. In the subsequent sections of this chapter, we will tell you how to do this.
The first step is to replace the add method with the usual mathematical symbols. This can be done directly, because the + in Scala is a legal identifier. We can use + to define the method name. Now, you can implement a * method to implement multiplication. The result is displayed in code 6.4:
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
Def this (N: INT) = This (n, 1)
Def + (that: Rational): Rational =
New Rational (
Numer * That. denom + that. numer * denom,
Denom * That. denom
)
Def * (that: Rational): Rational =
New Rational (numer * That. numer, denom * That. denom)
Override def tostring = numer + "/" + denom
Private def gcd (A: int, B: INT): Int =
If (B = 0) A else gcd (B, A % B)
}
Code 6.4 rational with Operator Methods
With the rational class defined in this way, you can write as follows:
Scala> Val x = New Rational (1, 2)
X: Rational = 1/2
Scala> Val y = New Rational (2, 3)
Y: Rational = 2/3
Scala> X + Y
Res32: Rational = 7/6
As in the past, the syntax format in the last line entered is equal to a method call. You can also write:
Scala> X. + (y)
Res33: rationally = 7/6
However, the write is not readable.
Another thing to mention is that, based on the scala operator priority rules mentioned in section 5.8, the * method in rational is stronger than the + method. Or, the expressions related to the + and * operations in rational will behave as expected. For example, x + x * Y is treated as X + (x * Y) instead of (x + x) * Y:
Scala> X + x * y
Res34: rationally = 5/6
Scala> (x + x) * y
Res35: rationally = 2/3
Scala> X + (x * Y)
Res36: Rational = 5/6
1.10 Scala identifier
Now you have seen two ways in Scala to form identifiers: alphanumeric and operator. Scala has flexible rules for creating identifiers. In addition to these two types, you will see two other types. This section describes the composition of all the four identifiers.
Alphanumeric identifier:Alphanumeric identifierStart with a letter or underline, followed by letters, numbers, or underscores. '$' Is also considered as a letter, but is reserved as an identifier generated by the scala compiler. The identifier in the user program should not contain the '$' character. Although it can be compiled, this may cause a name conflict with the identifier generated by the scala compiler.
Scala complies with Java's camper [5] identifiers, such as tostring and hashset. Although underlines are valid in identifiers, they are not commonly used in Scala programs, in part because they are used to maintain consistency with Java, also, the underline has many other non-identifier usage in scala code. Therefore, it is best to avoid using identifiers such as to_string ,__ init __, or name. Fields, method parameters, local variables, and the hump name of the function should start with lowercase letters, such as length, flatmap, and S. Classes and traits should start with an uppercase letter, such as bigint, list, And unbalancedtreemap. [6]
Note:
An underline is used at the end of the identifier. For example, if you try to write a definition such as "Val name _: Int = 1", you will receive a compiler error.. The compiler will think that you normally define a variable named "name. To compile the code, you need to insert an extra space before the colon, for example, "Val name _: Int = 1 ".
The difference between Scala and Java is the constant name. Scala,ConstantThis word is not equivalent to Val. Although Val remains unchanged after initialization, it is still a variable. For example,The method parameter is Val, but each time the method is called, these Val values can represent different values. While constants are more persistent. For example, scala. Math. Pi is defined as a double precision value close to the real number P, indicating the ratio of the circumference to its diameter. This value is unlikely to change, so pi is obviously a constant. You can also use constants to give your codeMagic Number:Magic numberThe name of the value to be used: the text value does not have the ability to interpret it. If it appears in multiple places, it will become extremely bad. You may also need to define constants used in pattern matching. Use Cases will be described in Section 15.2. In Java, constant names are all capitalized and words are separated by underscores, such as max_value or Pi. In Scala, the first letter must be capitalized. Therefore, Java-Style Constant names, such as x_offset, can also be used in Scala,Scala's convention is that constants also use the camper style, such as xoffset..
Operator identifier:Operator identifierIt consists of one or more operator characters. Operator characters include the following: + ,:,?,~ Or # printable ASCII characters. [7] The following are examples of operator identifiers:
++: <?> :->
The Scala compiler converts the internal "Smash" operator identifier to a valid Java identifier embedded with '$. For example, the identifier:-> is expressed internally as $ colon $ minus $ greater. If you want to access this identifier from Java code, you should use this internal expression.
Operator identifiers in Scala can become arbitrary, so there are some minor differences between Java and Scala. In Java, input x <-y is split into four vocabulary characters, so writing X <-y is no different. In Scala, <-is split as an identifier to get x <-y. If you want to get the first explanation, add a space between '<' and. This is probably not a problem in actual application, because no one will write x <-y in Java without any spaces or parentheses.
Hybrid identifier:Mixed identifierIt consists of letters and numbers followed by underscores and an operator identifier. For example, unary _ + is used as the method name for defining the '+' operator of a dollar. Alternatively, myvar _ = is used as the method name for defining the value assignment operator. The mixed identifier format myvar _ = is generated by the scala compiler to supportAttribute:Property.
Text identifier:Literal identifierIt is any string that is enclosed. For example:
'X' <clinit> ''ield'
The idea is that you can place any string recognized during runtime between the backquotes as an identifier. The result is always a Scala identifier. This rule is valid even if the name included in the backquotes is a reserved Scala word. The yield Method for accessing static data in the Java Thread class is a typical use case. You cannot write thread. Yield () because yield is a reserved word for Scala. However, you can still reference the method name in the back quotes, such as thread. 'yield '().
1.11 method overload
Return to the rational class. After the last change, you can add and multiply scores with Natural styles. But don't forget there is a hybrid operation. For example, you cannot multiply a score with an integer because the operands of '*' can only be scores. Therefore, you cannot write r * 2 for the score r. It must be written as R * New Rational (2), which does not look pretty. To make it easier for rational to use, you can add a new method to execute addition and multiplication between scores and integers on the class. Now that we have reached this point, we can add subtraction and division. The result is displayed in code 6.5:
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
Def this (N: INT) = This (n, 1)
Def + (that: Rational): Rational =
New Rational (
Numer * That. denom + that. numer * denom,
Denom * That. denom
)
Def + (I: INT): Rational =
New Rational (numer + I * denom, denom)
Def-(that: Rational): Rational =
New Rational (
Numer * That. denom-That. numer * denom,
Denom * That. denom
)
Def-(I: INT): Rational =
New Rational (numer-I * denom, denom)
Def * (that: Rational): Rational =
New Rational (numer * That. numer, denom * That. denom)
Def * (I: INT): Rational =
New Rational (numer * I, denom)
DEF/(that: Rational): Rational =
New Rational (numer * That. denom, denom * That. numer)
DEF/(I: INT): Rational =
New Rational (numer, denom * I)
Override def tostring = numer + "/" + denom
Private def gcd (A: int, B: INT): Int =
If (B = 0) A else gcd (B, A % B)
}
Code 6.5 contains the rational
Now each mathematical method has two versions: one with a score as a parameter and the other with an integer. Or you can say that these method names areOverload:OverloadBecause each name is currently used by multiple methods. For example, the name + is used by one method with rational and another with Int. In method calls, the compiler will pick out the version of the overloaded method that matches the parameter type correctly. For example, if the X. + (y) parameter Y is rational, the compiler selects the + method with the rational parameter for use. If the parameter is an integer, the compiler selects the + method with the int parameter for replacement. If you try to enter:
Scala> Val x = New Rational (2, 3)
X: Rational = 2/3
Scala> X * x
Res37: rationally = 4/9
Scala> X * 2
Res38: Rational = 4/3
You will see that * the call of a method depends on the type of the right operand in each example.
Note:
Scala's process of distinguishing overload methods is very similar to that of Java. Under any circumstances, the selected overloaded version is the most consistent with the static type of the parameter. Sometimes, if there are more than one of the most suitable versions; in this case, the compiler will give you a "reference fuzzy" error..
1.12 implicit conversion
Now you can write r * 2. Maybe you want to swap the operands, just like 2 * r. Unfortunately, you cannot do this:
Scala> 2 * R
<Console>: 7: Error: overloaded method value * with alternatives
(Double) Double <and> (float) float <and> (long) Long <and> (INT) int
<And> (char) int <and> (short) int <and> (byte) int cannot be
Applied to (rational)
Val RES2 = 2 * R
Bytes
The problem here is that 2 * r is equivalent to 2. * (R), so this is a method call on Integer 2. But the int class does not have the multiplication with the rational parameter-no way, because the class rational is not the standard class of the scala library.
However, scala has another way to solve this problem: You can create an implicit conversion that automatically converts Integers to scores as needed. Try to add this line of code to the interpreter:
Scala> implicit def inttorational (X: INT) = New Rational (X)
This line of code defines the conversion method from int to rational. The implicit modifier before the method tells the compiler to automatically call it in several cases. After the conversion is defined, You can retry the previous failed example:
Scala> Val r = New Rational (2, 3)
R: Rational = 2/3
Scala> 2 * R
Res0: Rational = 4/3
Note that implicit conversions must be defined within the scope of the action. If you put the implicit method definition within the class rational, it will not be within the scope of the interpreter. Now, you need to define it directly in the interpreter.
As you can see in this example, implicit conversion is a very powerful technology that makes the database more flexible and convenient. They are so powerful that they are easily misused. In Chapter 2, you will find more details about Implicit conversions, including the ways to bring them into the scope of action as needed.
Note:
In fact, if implicit conversion is defined, the previous rational class does not even need to define two sets of Methods: only the operation on the rational can be defined. implicit conversion will automatically convert the operands to instances of the rational class.
1.13 warning
As demonstrated in this chapter, using operator names to create methods and defining implicit conversions can help you design libraries that make customer code simpler and easier to understand. Scala gives you a lot of design capabilities that are easy to use, but keep in mind the responsibilities of capabilities.
If you use it without skill, the operator method and implicit conversion will make the customer's code hard to read and understand. Because implicit conversions are implicitly applied by the compiler, rather than explicitly written in the source code, it is not obvious to the client programmer which implicit conversions are applied. And although the operator method usually makes the Customer Code more concise, it only makes the program easier to read when the customer programmer can recognize and remember the meaning of each operator.
When designing a database, you should keep in mind the goal, not just to make the Customer Code concise, but to make it more readable and understandable. Simplicity is often an important part of readability, but it cannot be concise. By designing a library of Customer Code that is concise, readable, and easy to understand, you will help customer programmers to work in more places.
[1] The require method is defined on the isolated object predef In the scala package. As mentioned in section 4.4, members of the predef object have been automatically introduced into each Scala source file.
[2] Actually, when that refers to the object that calls add, rational can be added to itself. But because you can pass any rational object to add, the compiler still won't let you say that. n.
[3] in Section 10.6, you will findParameterized domain:Parametric FieldProvides shortcuts for writing the same code.
[4] Although N and D are used in class functions, since they are only used within the constructor, the scala compiler will not automatically construct the domain for them. So for the code, the scala compiler will generate a class with two int fields: numer and denom.
[5] This style is calledCamper type:Camel caseBecause the identifier is composed of embedded words with uppercase letters.
[6] In section 16.5, you will see that sometimes you needUse Case:Case classA special class is a name consisting of only operator characters. For example, scala APIs include a class called: To facilitate schema matching in the list.
[7] More accurately, operator characters belong to the Unicode set of mathematical symbols (SM) or other symbols (SO), or are not letters, numbers, Parentheses, square brackets, braces, single or double quotation marks, or underscores, periods, semicolons, colons, and seven ASCII characters that are returned.