Introduction
It's a direct migration of the dwango tutorial, where you'll study, edit it, and replace it with your own terms.
Now let's talk about class definitions in Scala. Please note that it is assumed that you know the Java class.
Classes in Scala are not much different from Java language classes, except for notation. Scala class definitions take the form:
class <name of the class> '(' (<Argument name 1> : <Argument type 1>, <Argument name 2>: <Argument type 2> ...)? ')' {
(<Field definition> | <Method definition> )*
}
For example, suppose you want to define a class Point that represents a point. Suppose Point consists of a field x (Int type) and a field y (Int type) that represent the x coordinate. Writing this class Point in Scala looks like this:
class Point(_x: Int, _y: Int) {
val x = _x
val y = _y
}
If you want to define a field with the same name as the argument of the constructor and expose it, you can also write it short as follows.
class Point(val x: Int, val y: Int)
There is a constructor argument definition immediately after the class name val / var allows constructor arguments to be exposed as fields Notice the point. First and foremost, Scala uses only one constructor per class. This constructor is treated specially in Scala as the primary constructor. Although it is grammatically possible to define multiple constructors, it is rarely used in practice. If you want to provide a way to create multiple objects, you often define it as an object's apply method.
The second point is that if you add val / var to the argument of the primary constructor, the field will be exposed and can be accessed from the outside. Note that the scope of the arguments of the primary constructor extends to the entire class definition. Therefore, you can refer to the constructor argument directly from the method definition as shown below.
class Point(val x: Int, val y: Int) {
def +(p: Point): Point = {
new Point(x + p.x, y + p.y)
}
override def toString(): String = "(" + x + ", " + y + ")"
}
The + method definition has already appeared as an example of the method definition earlier, but in general, it takes the following form.
(private([this | <package name>])? | protected([<package name>])?)? def <Method name> '('
(<Argument name> :Argument type(, Argument name : <Argument type>)*)?
')': <Return type> = <Body>
In practice, it will often take the following form using a block expression.
(private([this | <package name>])? | protected([<package name>])?)? def <Method name> '('
(<Argument name> :Argument type(, Argument name : <Argument type>)*)?
')': <Return type> = {
(<formula> (; | <new line>)?)*
}
This is just the case when the method body consists of a block expression, and there is no dedicated syntax for enclosing the method definition in {}.
Even if you omit the return type, it will infer the type except in special cases, but for readability, make a habit of specifying the return type. With private, the method can only be accessed within that class, and with protected, it can only be accessed by derived classes. With private [this], it can only be accessed from the same object. Also, if you add private [package name], you can access only from those that belong to the same package, and if you add protected [package name], you can access from all those that belong to the same package in addition to the derived class. Will be. If neither private nor protected is attached, the method is considered public.
Let's use the Point class defined earlier from the REPL.
scala> class Point(val x: Int, val y: Int) {
| def +(p: Point): Point = {
| new Point(x + p.x, y + p.y)
| }
| override def toString(): String = "(" + x + ", " + y + ")"
| }
defined class Point
scala> val p1 = new Point(1, 1)
p1: Point = (1, 1)
scala> val p2 = new Point(2, 2)
p2: Point = (2, 2)
scala> p1 + p2
res0: Point = (3, 3)
The method can be defined to have multiple argument lists as follows:
(private([this | <package name>])? | protected([<package name>])?)? def <Method name> '('
(<Argument name> :Argument type(, Argument name : <Argument type>)*)?
')'( '('
(<Argument name> :Argument type(, Argument name : <Argument type>)*)?
')' )* : <Return type> = <Body type>
Methods with multiple argument lists can be used in combination with Scala's syntactic sugar to create fluent APIs, needed for implicit parameters described below, or used to assist type inference. .. Let's define an addition method with multiple argument lists.
scala> class Adder {
| def add(x: Int)(y: Int): Int = x + y
| }
defined class Adder
scala> val adder = new Adder()
adder: Adder = Adder@55f0d6ee
scala> adder.add(2)(3)
res1: Int = 5
scala> val fun = adder.add(2) _
fun: Int => Int = $$Lambda$7309/854803072@56ddbb41
scala> fun(3)
res2: Int = 5
Methods with multiple argument lists will be called in the form obj.method (x) (y) instead of the form obj.method (x, y). You can also create a new function (partial application) by applying only the first argument, as in the example at the bottom.
You can also create a method that simply has multiple arguments without using a multi-argument list, like this:
scala> class Adder {
| def add(x: Int, y: Int): Int = x + y
| }
defined class Adder
scala> val adder = new Adder()
adder: Adder = Adder@2fb31283
scala> adder.add(2, 3)
res3: Int = 5
scala> val fun: Int => Int = adder.add(2, _)
fun: Int => Int = $$Lambda$7310/1712767810@7dbbe2d8
scala> fun(3)
res4: Int = 5
The field definition is
(private([this | <package name>])? | protected([<package name>])?)? (val | var) <Field name>: <Field type> = <Initialization formula>
It takes the form of. If it is val, it is an immutable field, and if it is var, it is a mutable field. Also, if private is added, the field can be accessed only within that class, and if protected is added, the field can be accessed only from derived classes of that class. Adding private [this] makes it accessible only from the same object. Furthermore, if you add private [
At that point, you may not be able to write an implementation, and you may want to give an implementation of a method or field when inheriting, which will be described later. To handle these cases, Scala allows you to define abstract members. Abstract members can be methods or fields, and for methods:
(private([this | <package name>])? | protected([<package name>])?)? def <Method name> '('
(<Argument name> :Argument type(, Argument name : <Argument type>)*)?
')': <Return type>
The field definition looks like this:
(private([this | <package name>])? | protected([<package name>])?)? (val | var) <Field name>: <Field type>
It is the same as a normal method or field definition, except that the method or field is empty. Also, a class that has one or more abstract methods must be declared as an abstract class. For example, an abstract class XY with x and y coordinates is defined as follows: The point is that you need to prefix the class with the abstract modifier.
scala> abstract class XY {
| def x: Int
| def y: Int
| }
defined class XY
Scala classes, like Java classes, can be inherited. Inheritance has two purposes. One is to reuse the implementation by using the superclass implementation in subclasses by inheritance. The other is to standardize processing by having multiple subclasses inherit the interface of a common superclass1. It is known that implementation inheritance has problems such as behavior when method and field names conflict due to multiple inheritance, and Java limits implementation inheritance to only one. Java 8 allows interfaces to have a default implementation, but with the limitation that variables cannot. Scala uses a mechanism called traits to inherit multiple implementations, but traits are discussed in a separate section.
This section describes normal Scala class inheritance. Class inheritance in Scala has the following syntax:
class <name of the class> <Class arguments> (extends <Super class>)? (with <Trait name>)* {
(<Field definition> | <Method definition>)*
}
The trait name is not used here, but will be explained later in the traits section. Inheritance works like a Java class, except that you must use the override keyword when overriding existing methods. For example, you can do the following:
scala> class APrinter() {
| def print(): Unit = {
| println("A")
| }
| }
defined class APrinter
scala> class BPrinter() extends APrinter {
| override def print(): Unit = {
| println("B")
| }
| }
defined class BPrinter
scala> new APrinter().print
A
scala> new BPrinter().print
B
If you remove the override keyword here, the following message will be output and a compile error will occur.
scala> class BPrinter() extends APrinter {
| def print(): Unit = {
| println("B")
| }
| }
<console>:14: error: overriding method print in class APrinter of type ()Unit;
method print needs `override' modifier
def print(): Unit = {
^
Java often makes the mistake of unknowingly defining a new method with the intention of overriding an existing method, but Scala uses the override keyword to address this issue at the language level.
Next time we will study objects.
This document is CC BY-NC-SA 3.0
It is distributed under.
https://dwango.github.io/scala_text/
Recommended Posts