Introduction
Il s'agit d'une migration directe du didacticiel dwango, où vous allez l'étudier, le modifier et le remplacer par vos propres termes.
Parlons maintenant des définitions de classe dans Scala. Veuillez noter qu'il est supposé que vous connaissez la classe Java.
Les classes de Scala ne sont pas très différentes des classes de langage Java, sauf pour la notation. La définition de classe de Scala prend la forme:
class <nom de la classe> '(' (<Nom de l'argument 1> : <Argument de type 1>, <Nom de l'argument 2>: <Argument de type 2> ...)? ')' {
(<Définition du champ> | <Définition de la méthode> )*
}
Par exemple, supposons que vous souhaitiez définir une classe Point qui représente un point. Supposons que Point se compose d'un champ x (type Int) et d'un champ y (type Int) qui représentent les coordonnées x. L'écriture de ce point de classe dans Scala ressemble à ceci:
class Point(_x: Int, _y: Int) {
val x = _x
val y = _y
}
Si vous souhaitez définir un champ avec le même nom que l'argument constructeur et l'exposer, vous pouvez l'écrire court comme suit.
class Point(val x: Int, val y: Int)
Il y a une définition d'argument de constructeur immédiatement après le nom de la classe val / var permet d'exposer les arguments du constructeur sous forme de champs Remarquez le point. Tout d'abord, Scala n'utilise qu'un seul constructeur par classe. Scala traite ce constructeur spécialement comme le constructeur principal. Bien qu'il soit grammaticalement possible de définir plusieurs constructeurs, il est rarement utilisé dans la pratique. Si vous souhaitez fournir un moyen de créer plusieurs objets, vous le définissez souvent en tant que méthode d'application d'un objet.
Le deuxième point est que si vous ajoutez val / var à l'argument du constructeur principal, le champ sera exposé et sera accessible de l'extérieur. Notez que la portée des arguments du constructeur principal s'étend à toute la définition de classe. Par conséquent, vous pouvez faire référence à l'argument constructeur directement à partir de la définition de méthode comme indiqué ci-dessous.
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 + ")"
}
La définition de méthode + est déjà apparue comme un exemple de la définition de méthode plus tôt, mais en général, elle prend la forme suivante.
(private([this | <nom du paquet>])? | protected([<nom du paquet>])?)? def <Nom de la méthode> '('
(<Nom de l'argument> :Type d'argument(, Nom de l'argument : <Type d'argument>)*)?
')': <Type de retour> = <Corps>
En pratique, il prendra souvent la forme suivante en utilisant une expression de bloc.
(private([this | <nom du paquet>])? | protected([<nom du paquet>])?)? def <Nom de la méthode> '('
(<Nom de l'argument> :Type d'argument(, Nom de l'argument : <Type d'argument>)*)?
')': <Type de retour> = {
(<formule> (; | <nouvelle ligne>)?)*
}
C'est juste le cas lorsque le corps de la méthode consiste en une expression de bloc et qu'il n'y a pas de syntaxe dédiée pour inclure la définition de méthode dans {}.
Même si vous omettez le type de retour, il inférera le type sauf dans des cas particuliers, mais pour la lisibilité, prenez l'habitude de spécifier le type de retour. Avec private, la méthode n'est accessible que dans cette classe, et avec protected, elle n'est accessible que par des classes dérivées. Avec private [this], il n'est accessible qu'à partir du même objet. De plus, si vous ajoutez un [nom du package] privé, vous ne pouvez accéder qu'à ceux qui appartiennent au même package, et si vous ajoutez [nom du package] protégé, vous pouvez accéder à partir de tous ceux qui appartiennent au même package en plus de la classe dérivée. Sera. Si ni privé ni protégé n'est attaché, la méthode est considérée comme publique.
Utilisons la classe Point définie précédemment à partir de 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)
La méthode peut être définie pour avoir plusieurs listes d'arguments comme suit:
(private([this | <nom du paquet>])? | protected([<nom du paquet>])?)? def <Nom de la méthode> '('
(<Nom de l'argument> :Type d'argument(, Nom de l'argument : <Type d'argument>)*)?
')'( '('
(<Nom de l'argument> :Type d'argument(, Nom de l'argument : <Type d'argument>)*)?
')' )* : <Type de retour> = <Type de corps>
Les méthodes avec plusieurs listes d'arguments peuvent être utilisées en combinaison avec la syntaxe sucrée de Scala pour créer des API fluides, nécessaires pour les paramètres implicites décrits ci-dessous, ou utilisées pour faciliter l'inférence de type. .. Définissons une méthode d'addition avec plusieurs listes d'arguments.
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
Les méthodes avec plusieurs listes d'arguments seront appelées sous la forme obj.method (x) (y) au lieu de la forme obj.method (x, y). Vous pouvez également créer une nouvelle fonction (application partielle) en appliquant uniquement le premier argument comme dans l'exemple en bas.
Vous pouvez également créer une méthode qui a simplement plusieurs arguments sans utiliser de liste à plusieurs arguments, comme ceci:
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
La définition du champ est
(private([this | <nom du paquet>])? | protected([<nom du paquet>])?)? (val | var) <Nom de domaine>: <Type de champ> = <Formule d'initialisation>
Cela prend la forme de. Si c'est val, c'est un champ immuable, et s'il est var, c'est un champ mutable. De plus, si private est ajouté, le champ n'est accessible que dans cette classe, et si protected est ajouté, le champ n'est accessible qu'à partir des classes dérivées de cette classe. Si vous ajoutez private [this], il ne sera accessible qu'à partir du même objet. De plus, si vous ajoutez private [
À ce stade, vous ne pourrez peut-être pas écrire une implémentation et vous souhaiterez peut-être donner une implémentation d'une méthode ou d'un champ lors de l'héritage, ce qui sera décrit plus tard. Pour gérer de tels cas, Scala vous permet de définir des membres abstraits. Les membres abstraits peuvent être des méthodes ou des champs, et pour les méthodes:
(private([this | <nom du paquet>])? | protected([<nom du paquet>])?)? def <Nom de la méthode> '('
(<Nom de l'argument> :Type d'argument(, Nom de l'argument : <Type d'argument>)*)?
')': <Type de retour>
La définition du champ ressemble à ceci:
(private([this | <nom du paquet>])? | protected([<nom du paquet>])?)? (val | var) <Nom de domaine>: <Type de champ>
C'est la même chose qu'une méthode ou une définition de champ normale, sauf qu'il n'y a pas de contenu de la méthode ou du champ. En outre, une classe qui a une ou plusieurs méthodes abstraites doit être déclarée en tant que classe abstraite. Par exemple, une classe abstraite XY avec des coordonnées x et y est définie comme suit: Le fait est que vous devez préfixer la classe avec le modificateur abstrait.
scala> abstract class XY {
| def x: Int
| def y: Int
| }
defined class XY
Les classes Scala, comme les classes Java, peuvent être héritées. L'héritage a deux objectifs. La première consiste à réutiliser l'implémentation en utilisant l'implémentation de la superclasse dans la sous-classe par héritage. L'autre consiste à standardiser le traitement en faisant hériter de plusieurs sous-classes de l'interface d'une superclasse commune1. Il est connu que l'héritage d'implémentation présente des problèmes tels que le comportement lorsque les noms de méthode et de champ sont en conflit en raison de plusieurs héritages, et Java limite l'héritage d'implémentation à un seul. Java 8 permet aux interfaces d'avoir une implémentation par défaut, mais avec la limitation que les variables ne peuvent pas. Scala utilise un mécanisme appelé traits pour hériter de plusieurs implémentations, mais les traits sont traités dans une section séparée.
Cette section décrit l'héritage des classes Scala normales. L'héritage de classe dans Scala a la syntaxe suivante:
class <nom de la classe> <Argument de classe> (extends <Super classe>)? (with <Nom Trate>)* {
(<Définition du champ> | <Définition de la méthode>)*
}
Le nom du trait n'est pas utilisé ici, mais sera expliqué plus loin dans la section trait. L'héritage fonctionne de la même manière que les classes Java, sauf que vous devez utiliser le mot-clé override lorsque vous remplacez des méthodes existantes. Par exemple, vous pouvez effectuer les opérations suivantes:
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
Si vous supprimez ici le mot-clé override, le message suivant sera affiché et une erreur de compilation se produira.
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 fait souvent l'erreur de définir sans le savoir une nouvelle méthode avec l'intention de remplacer une méthode existante, mais Scala utilise le mot-clé override pour résoudre ce problème au niveau du langage.
La prochaine fois, nous étudierons les objets.
Ce document est CC BY-NC-SA 3.0
Il est distribué sous.
https://dwango.github.io/scala_text/
Recommended Posts