You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Аннотации используются для передачи метаданных при объявлении. Например, аннотация `@deprecated` перед объявлением метода, заставит компилятор вывести предупреждение, если этот метод будет использован.
12
-
```
12
+
13
+
{% tabs annotations_1 class=tabs-scala-version %}
14
+
{% tab 'Scala 2' for=annotations_1 %}
15
+
16
+
```scala mdoc:fail
13
17
objectDeprecationDemoextendsApp {
14
18
@deprecated("deprecation message", "release # which deprecates method")
15
19
defhello="hola"
16
20
17
-
hello
21
+
hello
18
22
}
19
23
```
24
+
25
+
{% endtab %}
26
+
{% tab 'Scala 3' for=annotations_1 %}
27
+
28
+
```scala
29
+
objectDeprecationDemoextendsApp:
30
+
@deprecated("deprecation message", "release # which deprecates method")
31
+
defhello="hola"
32
+
33
+
hello
34
+
```
35
+
36
+
{% endtab %}
37
+
{% endtabs %}
38
+
20
39
Такой код скомпилируется, но компилятор выдаст предупреждение: "there was one deprecation warning".
21
40
22
41
Аннотация применяется к первому идущему после нее объявлению или определению. Допускается использование сразу нескольких аннотаций следующих друг за другом. Порядок, в котором приводятся аннотации, не имеет значения.
23
42
24
43
## Аннотации, обеспечивающие корректность работы кода
44
+
25
45
Некоторые аннотации приводят к невозможности компиляции, если условие (условия) не выполняется. Например, аннотация `@tailrec` гарантирует, что метод является [хвостовой рекурсией](https://ru.wikipedia.org/wiki/%D0%A5%D0%B2%D0%BE%D1%81%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F). Хвостовая рекурсия помогает держать потребление памяти на постоянном уровне. Вот как она используется в методе, который вычисляет факториал:
26
46
47
+
{% tabs annotations_2 class=tabs-scala-version %}
48
+
{% tab 'Scala 2' for=annotations_2 %}
49
+
27
50
```scala mdoc
28
51
importscala.annotation.tailrec
29
52
@@ -36,8 +59,30 @@ def factorial(x: Int): Int = {
36
59
factorialHelper(x, 1)
37
60
}
38
61
```
39
-
Метод `factorialHelper` имеет аннотацию `@tailrec`, которая гарантирует, что метод действительно является хвостовой рекурсией. Если бы мы изменили реализацию `factorialHelper` так как указано далее, то компиляция бы провалилась:
62
+
63
+
{% endtab %}
64
+
{% tab 'Scala 3' for=annotations_2 %}
65
+
66
+
```scala
67
+
importscala.annotation.tailrec
68
+
69
+
deffactorial(x: Int):Int=
70
+
71
+
@tailrec
72
+
deffactorialHelper(x: Int, accumulator: Int):Int=
73
+
if x ==1then accumulator else factorialHelper(x -1, accumulator * x)
74
+
factorialHelper(x, 1)
40
75
```
76
+
77
+
{% endtab %}
78
+
{% endtabs %}
79
+
80
+
Метод `factorialHelper` имеет аннотацию `@tailrec`, которая гарантирует, что метод действительно является хвостовой рекурсией. Если бы мы изменили реализацию `factorialHelper` так как указано далее, то компиляция бы провалилась:
81
+
82
+
{% tabs annotations_3 class=tabs-scala-version %}
83
+
{% tab 'Scala 2' for=annotations_3 %}
84
+
85
+
```scala mdoc:fail
41
86
importscala.annotation.tailrec
42
87
43
88
deffactorial(x: Int):Int= {
@@ -48,77 +93,155 @@ def factorial(x: Int): Int = {
48
93
factorialHelper(x)
49
94
}
50
95
```
51
-
Мы бы получили сообщение "Recursive call not in tail position"(Рекурсивный вызов не в хвостовой позиции).
52
96
97
+
{% endtab %}
98
+
{% tab 'Scala 3' for=annotations_3 %}
99
+
100
+
```scala
101
+
importscala.annotation.tailrec
102
+
103
+
deffactorial(x: Int):Int=
104
+
@tailrec
105
+
deffactorialHelper(x: Int):Int=
106
+
if x ==1then1else x * factorialHelper(x -1)
107
+
factorialHelper(x)
108
+
```
109
+
110
+
{% endtab %}
111
+
{% endtabs %}
112
+
113
+
Мы бы получили сообщение "Recursive call not in tail position"(Рекурсивный вызов не в хвостовой позиции).
53
114
54
115
## Аннотации, влияющие на генерацию кода
116
+
117
+
{% tabs annotations_4 class=tabs-scala-version %}
118
+
{% tab 'Scala 2' for=annotations_4 %}
119
+
55
120
Некоторые аннотации типа `@inline` влияют на сгенерированный код (т.е. в результате сам код вашего jar-файл может отличаться). Такая аннотация означает вставку всего кода в тело метода вместо вызова. Полученный байт-код длиннее, но, надеюсь, работает быстрее. Использование аннотации `@inline` не гарантирует, что метод будет встроен, но заставит компилятор сделать это, если и только если будут соблюдены некоторые разумные требования к размеру сгенерированного кода.
56
121
57
-
### Java аннотации ###
122
+
{% endtab %}
123
+
{% tab 'Scala 3' for=annotations_4 %}
124
+
125
+
Некоторые аннотации типа `@main` влияют на сгенерированный код (т.е. в результате сам код вашего jar-файл может отличаться).
126
+
Аннотация `@main` к методу создает исполняемую программу, которая вызывает метод как точку входа.
127
+
128
+
{% endtab %}
129
+
{% endtabs %}
130
+
131
+
### Java аннотации
132
+
58
133
Есть некоторые отличия синтаксиса аннотаций, если пишется Scala код, который взаимодействует с Java.
59
134
60
135
**Примечание:**Убедитесь, что вы используете опцию `-target:jvm-1.8` с аннотациями Java.
61
136
62
137
Java имеет определяемые пользователем метаданные в виде [аннотаций](https://docs.oracle.com/javase/tutorial/java/annotations/). Ключевой особенностью аннотаций является то, что они задаются в виде пар ключ-значение для инициализации своих элементов. Например, если нам нужна аннотация для отслеживания источника какого-то класса, мы можем определить её как
Этот синтаксис достаточно перегруженный, если аннотация содержит только один элемент (без значения по умолчанию), поэтому, если имя указано как `value`, оно может быть применено в Java с помощью конструктора-подобного синтаксиса:
88
181
89
-
```
182
+
{% tabs annotations_8 %}
183
+
{% tab 'Java'for=annotations_8 %}
184
+
185
+
```java
90
186
@interfaceSourceURL {
91
187
publicStringvalue();
92
188
publicStringmail() default "";
93
189
}
94
190
```
95
191
192
+
{% endtab %}
193
+
{% endtabs %}
194
+
96
195
А затем можно использовать следующим образом
97
196
98
-
```
197
+
{% tabs annotations_9 %}
198
+
{% tab 'Java' for=annotations_9 %}
199
+
200
+
```java
99
201
@SourceURL("https://coders.com/")
100
-
public class MyClass extends HisClass ...
202
+
publicclassMyJavaClassextendsTheirClass ...
101
203
```
102
204
205
+
{% endtab %}
206
+
{% endtabs %}
207
+
103
208
В этом случае Scala предоставляет такую же возможность
104
209
105
-
```
210
+
{% tabs annotations_10 %}
211
+
{% tab 'Scala 2 и 3'for=annotations_10 %}
212
+
213
+
```scala
106
214
@SourceURL("https://coders.com/")
107
215
classMyScalaClass ...
108
216
```
109
217
218
+
{% endtab %}
219
+
{% endtabs %}
220
+
110
221
Элемент `mail` был указан со значением по умолчанию, поэтому нам не нужно явно указывать его значение. Мы не можем смешивать эти два стиля в Java:
Copy file name to clipboardExpand all lines: _ru/tour/by-name-parameters.md
+34-2Lines changed: 34 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -9,13 +9,24 @@ previous-page: operators
9
9
---
10
10
11
11
_Вызов параметров по имени_ - это когда значение параметра вычисляется только в момент вызова параметра. Этот способ противоположен _вызову по значению_. Чтоб вызов параметра был по имени, необходимо просто указать `=>` перед его типом.
12
+
13
+
{% tabs by-name-parameters_1 %}
14
+
{% tab 'Scala 2 и 3' for=by-name-parameters_1 %}
15
+
12
16
```scala mdoc
13
17
defcalculate(input: =>Int) = input *37
14
18
```
19
+
20
+
{% endtab %}
21
+
{% endtabs %}
22
+
15
23
Преимущество вызова параметров по имени заключается в том, что они не вычисляются если не используются в теле функции. С другой стороны плюсы вызова параметров по значению в том, что они вычисляются только один раз.
16
24
17
25
Вот пример того, как мы можем реализовать условный цикл:
Метод `whileLoop` использует несколько списков параметров - условие и тело цикла. Если `condition` является верным, выполняется `body`, а затем выполняется рекурсивный вызов whileLoop. Если `condition` является ложным, то тело никогда не вычисляется, тк у нас стоит `=>` перед типом `body`.
Метод `whileLoop` использует несколько списков параметров - условие и тело цикла. Если `condition` является верным, выполняется `body`, а затем выполняется рекурсивный вызов whileLoop. Если `condition` является ложным, то тело никогда не вычисляется, тк у нас стоит `=>` перед типом `body`.
34
66
35
67
Теперь, когда мы передаем `i > 0` как наше условие `condition` и `println(i); i-= 1` как тело `body`, код ведет себя также как обычный цикл в большинстве языков программирования.
36
68
37
-
Такая возможность откладывать вычисления параметра до его использования может помочь повысить производительность, отсекая не нужные вычисления при определенных условиях.
69
+
Такая возможность откладывать вычисления параметра до его использования может помочь повысить производительность, отсекая не нужные вычисления при определенных условиях.
0 commit comments