8000 Refresh _ru/tour/higher-order-functions.md (#2794) · performantdata/docs.scala-lang@d47c4a9 · GitHub
[go: up one dir, main page]

Skip to content

Commit d47c4a9

Browse files
Refresh _ru/tour/higher-order-functions.md (scala#2794)
1 parent 6efe335 commit d47c4a9

File tree

1 file changed

+147
-9
lines changed

1 file changed

+147
-9
lines changed

_ru/tour/higher-order-functions.md

Lines changed: 147 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,73 @@ next-page: nested-functions
88
previous-page: mixin-class-composition
99
---
1010

11-
Функции высшего порядка могут принимать другие функции в качестве параметров или возвращать функцию в качестве результата.
12-
Такое возможно поскольку функции являются объектами первого класса в Scala.
13-
На текущем этапе терминология может казаться немного запутанной, мы используем следующую фразу "функция высшего порядка" как для методов, так и для функций, которые могут принимать другие функции в качестве параметров, или возвращать функции в качестве результата.
11+
Функции высшего порядка могут принимать другие функции в качестве параметров или возвращать функцию в качестве результата.
12+
Такое возможно поскольку функции являются объектами первого класса в Scala.
13+
На текущем этапе терминология может казаться немного запутанной, мы используем следующую фразу "функция высшего порядка" как для методов, так и для функций, которые могут принимать другие функции в качестве параметров, или возвращать функции в качестве результата.
1414

15-
Одним из наиболее распространенных примеров функции высшего порядка
15+
В чисто объектно-ориентированном мире рекомендуется избегать раскрытия методов,
16+
параметризованных функциями, которые могут привести к утечке внутреннего состояния объекта.
17+
Утечка внутреннего состояния может нарушить инварианты самого объекта, тем самым нарушив инкапсуляцию.
18+
19+
Одним из наиболее распространенных примеров функции высшего порядка
1620
является функция `map`, которая доступна в коллекциях Scala.
17-
```scala mdoc
18-
val salaries = Seq(20000, 70000, 40000)
21+
22+
{% tabs map_example_1 %}
23+
24+
{% tab 'Scala 2 и 3' for=map_example_1 %}
25+
26+
```scala mdoc:nest
27+
val salaries = Seq(20_000, 70_000, 40_000)
1928
val doubleSalary = (x: Int) => x * 2
2029
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)
2130
```
31+
32+
{% endtab %}
33+
34+
{% endtabs %}
35+
2236
`doubleSalary` - это функция, которая принимает один Int `x` и возвращает `x * 2`. В общем случае, кортеж (список имен в скобках) слева от стрелки `=>` - это список параметров, а значение выражения следует справа. Это же значение возвращается в качестве результата. В строке 3 к каждому элементу списка зарплат (salaries) применяется функция `doubleSalary`.
2337

2438
Чтобы сократить код, мы можем сделать функцию анонимной и передать ее напрямую в качестве аргумента в map:
39+
40+
{% tabs map_example_2 %}
41+
42+
{% tab 'Scala 2 и 3' for=map_example_2 %}
43+
2544
```scala mdoc:nest
26-
val salaries = Seq(20000, 70000, 40000)
45+
val salaries = Seq(20_000, 70_000, 40_000)
2746
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)
2847
```
48+
49+
{% endtab %}
50+
51+
{% endtabs %}
52+
2953
Обратите внимание, что в приведенном выше примере `x`не объявлен как `Int`. Это потому, что компилятор может вывести тип, основываясь на типе который ожидает функция map. Еще более элегантным способом написания этого же кода было бы таким:
3054

55+
{% tabs map_example_3 %}
56+
57+
{% tab 'Scala 2 и 3' for=map_example_3 %}
58+
3159
```scala mdoc:nest
32-
val salaries = Seq(20000, 70000, 40000)
60+
val salaries = Seq(20_000, 70_000, 40_000)
3361
val newSalaries = salaries.map(_ * 2)
3462
```
63+
64+
{% endtab %}
65+
66+
{% endtabs %}
67+
3568
Поскольку компилятор Scala уже знает тип параметров (Int), вам нужно только указать правую часть функции. Единственное условие заключается в том, что вместо имени параметра необходимо использовать `_` (в предыдущем примере это было `x`).
3669

3770
## Преобразование методов в функции
71+
3872
Также возможно передавать методы в качестве аргументов функциям более высокого порядка, поскольку компилятор Scala может преобразовать метод в функцию.
73+
74+
{% tabs Coercing_methods_into_functions class=tabs-scala-version %}
75+
76+
{% tab 'Scala 2' for=Coercing_methods_into_functions %}
77+
3978
```scala mdoc
4079
case class WeeklyWeatherForecast(temperatures: Seq[Double]) {
4180

@@ -44,11 +83,33 @@ case class WeeklyWeatherForecast(temperatures: Seq[Double]) {
4483
def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- передается метод convertCtoF
4584
}
4685
```
86+
87+
{% endtab %}
88+
89+
{% tab 'Scala 3' for=Coercing_methods_into_functions %}
90+
91+
```scala
92+
case class WeeklyWeatherForecast(temperatures: Seq[Double]):
93+
94+
private def convertCtoF(temp: Double) = temp * 1.8 + 32
95+
96+
def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- передается метод convertCtoF
97+
```
98+
99+
{% endtab %}
100+
101+
{% endtabs %}
102+
47103
Здесь метод `convertCtoF` передается в `forecastInFahrenheit`. Это возможно, потому что компилятор преобразовывает `convertCtoF` в функцию `x => ConvertCtoF(x)` (примечание: `x` будет сгенерированным именем, которое гарантированно будет уникальным в рамках своей области видимости).
48104

49105
## Функции, которые принимают функции
106+
50107
Одной из причин использования функций высшего порядка является сокращение избыточного кода. Допустим, вам нужны какие-то методы, которые могли бы повышать чью-то зарплату по разным условиям. Без создания функции высшего порядка это могло бы выглядеть примерно так:
51108

109+
{% tabs Functions_that_accept_functions_1 class=tabs-scala-version %}
110+
111+
{% tab 'Scala 2' for=Functions_that_accept_functions_1 %}
112+
52113
```scala mdoc
53114
object SalaryRaiser {
54115

@@ -63,8 +124,33 @@ object SalaryRaiser {
63124
}
64125
```
65126

127+
{% endtab %}
128+
129+
{% tab 'Scala 3' for=Functions_that_accept_functions_1 %}
130+
131+
```scala
132+
object SalaryRaiser:
133+
134+
def smallPromotion(salaries: List[Double]): List[Double] =
135+
salaries.map(salary => salary * 1.1)
136+
137+
def greatPromotion(salaries: List[Double]): List[Double] =
138+
salaries.map(salary => salary * math.log(salary))
139+
140+
def hugePromotion(salaries: List[Double]): List[Double] =
141+
salaries.map(salary => salary * salary)
142+
```
143+
144+
{% endtab %}
145+
146+
{% endtabs %}
147+
66148
Обратите внимание, что каждый из этих трех методов отличается только коэффициентом умножения. Для упрощения можно перенести повторяющийся код в функцию высшего порядка:
67149

150+
{% tabs Functions_that_accept_functions_2 class=tabs-scala-version %}
151+
152+
{% tab 'Scala 2' for=Functions_that_accept_functions_2 %}
153+
68154
```scala mdoc:nest
69155
object SalaryRaiser {
70156

@@ -74,20 +160,52 @@ object SalaryRaiser {
74160
def smallPromotion(salaries: List[Double]): List[Double] =
75161
promotion(salaries, salary => salary * 1.1)
76162

77-
def bigPromotion(salaries: List[Double]): List[Double] =
163+
def greatPromotion(salaries: List[Double]): List[Double] =
78164
promotion(salaries, salary => salary * math.log(salary))
79165

80166
def hugePromotion(salaries: List[Double]): List[Double] =
81167
promotion(salaries, salary => salary * salary)
82168
}
83169
```
84170

171+
{% endtab %}
172+
173+
{% tab 'Scala 3' for=Functions_that_accept_functions_2 %}
174+
175+
```scala
176+
object SalaryRaiser:
177+
178+
private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
179+
salaries.map(promotionFunction)
180+
181+
def smallPromotion(salaries: List[Double]): List[Double] =
182+
promotion(salaries, salary => salary * 1.1)
183+
184+
def greatPromotion(salaries: List[Double]): List[Double] =
185+
promotion(salaries, salary => salary * math.log(salary))
186+
187+
def hugePromotion(salaries: List[Double]): List[Double] =
188+
promotion(salaries, salary => salary * salary)
189+
```
190+
191+
{% endtab %}
192+
193+
{% endtabs %}
194+
85195
Новый метод, `promotion`, берет зарплату и функцию типа `Double => Double` (т.е. функция, которая берет Double и возвращает Double) и возвращает их произведение.
86196

197+
Методы и функции обычно выражают поведение или преобразование данных, поэтому наличие функций,
198+
которые компонуются на основе других функций, может помочь в создании общих механизмов.
199+
Эти типовые функции откладывают блокировку всего поведения операции,
200+
предоставляя клиентам возможность контролировать или дополнительно настраивать части самой операции.
87201
## Функции, возвращающие функции
88202

89203
Есть определенные случаи, когда вы хотите сгенерировать функцию. Вот пример метода, который возвращает функцию.
90204

205+
{% tabs Functions_that_return_functions class=tabs-scala-version %}
206+
207+
{% tab 'Scala 2' for=Functions_that_return_functions %}
208+
91209
```scala mdoc
92210
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
93211
val schema = if (ssl) "https://" else "http://"
@@ -101,4 +219,24 @@ val query = "id=1"
101219
val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
102220
```
103221

222+
{% endtab %}
223+
224+
{% tab 'Scala 3' for=Functions_that_return_functions %}
225+
226+
```scala
227+
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String =
228+
val schema = if ssl then "https://" else "http://"
229+
(endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
230+
231+
val domainName = "www.example.com"
232+
def getURL = urlBuilder(ssl=true, domainName)
233+
val endpoint = "users"
234+
val query = "id=1"
235+
val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
236+
```
237+
238+
{% endtab %}
239+
240+
{% endtabs %}
241+
104242
Обратите внимание, что возвращаемый тип urlBuilder`(String, String) => String`. Это означает, что возвращаемая анонимная функция принимает две строки и возвращает строку. В нашем случае возвращаемая анонимная функция `(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"`.

0 commit comments

Comments
 (0)
0