I touched Scala ~ [Class] ~

Introduction

image.png

It's a direct migration of the dwango tutorial, where you'll study, edit it, and replace it with your own terms.

class

Now let's talk about class definitions in Scala. Please note that it is assumed that you know the Java class.

Class definition

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

Method definition

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)

Method with multiple argument lists

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

Field definition

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 [], you can access only from the same package, and if you add protected [package name], you can access it from all those belonging to the same package in addition to the derived class. If neither private nor protected is attached, the field is considered public. Accessing fields with private [this] is a bit faster, as they are typically direct access to fields at the JVM level. It's a good idea to be aware of this when tuning performance at a fine level.

Abstract member

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

Inheritance

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.

end

Next time we will study objects.

reference

This document is CC BY-NC-SA 3.0

image.png It is distributed under.

https://dwango.github.io/scala_text/

Recommended Posts

I touched Scala ~ [Class] ~
I touched Scala
I touched Scala ~ [Object] ~
I touched Scala ~ [Trait] ~
I touched Scala ~ [Control syntax] ~
I first touched Java ②
I first touched Java ③
I first touched Java ④
I touched Scala ~ [Type parameters and displacement specification] ~
I first touched Java
I went to Scala Fukuoka 2019!
I made an eco server with scala
Note that I touched Android's SQLiteOpenHelper lightly
Shape Scala case class for easy viewing
I touched ODM for Developer ② Rule development