Scala: функции высшего порядка, неявные преобразования
Цели курса
- Понимать концепцию функций высшего порядка (функции как значения, анонимные функции, замыкания, каррирование)
- Освоение неявных преобразований и неявных параметров
- Освойте среду программирования параллелизма Akka
1. Функции высшего порядка
Scala сочетает в себе объектно-ориентированные и функциональные функции. В функциональных языках программирования функции являются «гражданами первого класса». Они находятся на том же уровне, что и другие типы, такие как Int, String и Class, и могут передаваться и передаваться, как и другие типы. переменных.
Функции высшего порядка содержат
- функционировать как значение
- анонимная функция
- Закрытие
- Карри и др.
1.1 Функции как ценности
В scala функции похожи на числа и строки, и функции можно передавать в метод. Полезно иметь возможность инкапсулировать алгоритмы, а затем передавать определенные действия методам.
Мы изучили метод отображения списка раньше, и он может получить функцию для завершения преобразования списка.
Пример
Пример описания
Преобразует каждый элемент списка целых чисел в соответствующее количество маленьких звездочек.
List(1, 2, 3...) => *, **, ***
шаг
- Создайте функцию, которая преобразует числа в указанное количество маленьких звездочек.
- Создайте список и вызовите метод карты
- список печати преобразован в
Код ссылки
val func: Int => String = (num:Int) => "*" * num
println((1 to 10).map(func))
1.2 Анонимные функции
определение
Приведенный выше код присваивает переменную функции (num:Int) => "*" * num, но такой способ написания немного многословен. В scala нет необходимости присваивать функции переменным, функции, которые не присваиваются переменным,анонимная функция
val list = List(1, 2, 3, 4)
// 字符串*方法,表示生成指定数量的字符串
val func_num2star = (num:Int) => "*" * num
print(list.map(func_num2star))
Пример
Оптимизируйте приведенный выше код, используя анонимные функции.
Код ссылки
println((1 to 10).map(num => "*" * num))
// 因为此处num变量只使用了一次,而且只是进行简单的计算,所以可以省略参数列表,使用_替代参数
println((1 to 10).map("*" * _))
1.3 Каррирование
В исходном коде scala и spark широко используется каррирование. Чтобы облегчить последующее чтение исходного кода, нам нужно понять каррирование.
определение
Каррирование — это процесс преобразования метода, который изначально принимал несколько параметров, в несколько списков параметров только с одним параметром.
[Не удалось передать изображение по внешней ссылке, исходный сайт может иметь механизм защиты от пиявки, рекомендуется сохранить изображение и загрузить его напрямую (img-Yitd5lcH-1625207556241)(/assets/1552811606951.png)]
Анализ процесса каррирования
Пример
Пример описания
- Напишите метод для завершения вычисления двух чисел типа Int
- Как инкапсулировать вычисление в функцию
- Используйте каррирование для достижения вышеуказанной операции
Код ссылки
// 柯里化:实现对两个数进行计算
def calc_carried(x:Double, y:Double)(func_calc:(Double, Double)=>Double) = {
func_calc(x, y)
}
def main(args: Intrray[String]): Unit = {
println(calc_carried(10.1, 10.2){
(x,y) => x + y
})
println(calc_carried(10, 10)(_ + _))
println(calc_carried(10.1, 10.2)(_ * _))
println(calc_carried(100.2, 10)(_ - _))
}
1.4 Закрытие
Закрытие на самом деле является функцией, за исключением того, что возвращаемое значение этой функции зависит от переменных, объявленных вне функции.
Его можно просто рассматривать как доступ к функции, которая не находится в текущей области.
Пример 1
определить замыкание
val y=10
val add=(x:Int)=>{
x+y
}
println(add(5)) // 结果15
Функция добавления является закрытием
Пример 2
Карри - это закрытие
def add(x:Int)(y:Int) = {
x + y
}
Приведенный выше код эквивалентен
def add(x:Int) = {
(y:Int) => x + y
}
2. Неявные преобразования и неявные параметры
Неявные преобразования и неявные параметры — очень уникальные функции scala, а также функции, которых нет в других языках программирования, таких как Java. Мы можем легко использовать неявные преобразования для расширения функциональности существующих классов. Позже, при написании параллельного программирования Akka, Spark SQL и Flink, вы увидите неявные преобразования и неявные параметры.
2.1 Определения
так называемыйнеявное преобразование, который объявлен с помощью ключевого слова implicit содин параметрМетоды. этоавтоматически вызывается, который автоматически преобразует один тип в другой.
Шаги для использования
- Определите метод неявного преобразования в объекте (используя неявный)
- Внедрите неявные преобразования (используя импорт) там, где необходимы неявные преобразования.
- Автоматически вызывать неявно преобразованный метод
Пример
Пример описания
Используйте неявное преобразование, чтобы File имел функцию чтения, чтобы читать содержимое текста в виде строки.
шаг
- Создайте класс RichFile, предоставляющий метод чтения для чтения содержимого файла в виде строки.
- Определите метод неявного преобразования для неявного преобразования объекта File в RichFile.
- Создайте файл, импортируйте неявное преобразование и вызовите метод чтения файла.
Код ссылки
class RichFile(val file:File) {
// 读取文件为字符串
def read() = {
Source.fromFile(file).mkString
}
}
object RichFile {
// 定义隐式转换方法
implicit def file2RichFile(file:File) = new RichFile(file)
}
def main(args: Array[String]): Unit = {
// 加载文件
val file = new File("./data/1.txt")
// 导入隐式转换
import RichFile.file2RichFile
// file对象具备有read方法
println(file.read())
}
2.2 Время неявных преобразований
- Когда объект вызывает метод или член, не существующий в классе, компилятор автоматически неявно преобразует объект
- Когда тип параметра в методе не соответствует целевому типу
2.3 Автоматически импортировать методы неявного преобразования
Ранее мы вручную использовали импорт для импорта неявных преобразований. Можно ли не импортировать вручную?
В scala, если в текущей области есть метод неявного преобразования, неявное преобразование импортируется автоматически.
Пример: определить метод неявного преобразования в объекте, где находится main
class RichFile(val f:File) {
// 将文件中内容读取成字符串
def read() = Source.fromFile(f).mkString
}
object ImplicitConvertDemo {
// 定义隐式转换方法
implicit def file2RichFile(f:File) = new RichFile(f)
def main(args: Array[String]): Unit = {
val f = new File("./data/textfiles/1.txt")
// 调用的其实是RichFile的read方法
println(f.read())
}
}
2.4 Неявные параметры
Методы могут принимать список параметров, помеченный как неявный. В этом случае компилятор будет искать значение по умолчанию и предоставлять его методу.
определение
- Добавьте список параметров после метода, и параметры будут изменены с помощью неявного
- Определите неявное значение неявной модификации в объекте
- При вызове метода список неявных параметров можно опустить, и компилятор автоматически найдет значение по умолчанию.
[!NOTE]
- Как и неявные преобразования, неявные параметры можно импортировать вручную с помощью import
- Импортируется автоматически, если в текущей области определено неявное значение.
Пример
Пример описания
- Определите метод, который включает входящее значение с префиксом и суффиксом разделителя.
- Разделители определяются с использованием неявных параметров
- вызовите метод и распечатайте тест
Код ссылки
// 使用implicit定义一个参数
def quote(what:String)(implicit delimiter:(String, String)) = {
delimiter._1 + what + delimiter._2
}
// 隐式参数
object ImplicitParam {
implicit val DEFAULT_DELIMITERS = ("<<<", ">>>")
}
def main(args: Array[String]): Unit = {
// 导入隐式参数
import ImplicitParam.DEFAULT_DELIMITERS
println(quote("李雷和韩梅梅"))
}
elimiter:(String, String)) = { delimiter._1 + what + delimiter._2 }
// неявный параметр объект ImplicitParam { неявное значение DEFAULT_DELIMITERS = (">>") }
def main(args: Array[String]): Unit = { // импорт неявных параметров импортировать ImplicitParam.DEFAULT_DELIMITERS
println(quote("李雷和韩梅梅"))
}