Scala: функции высшего порядка, неявные преобразования (4)

искусственный интеллект
Scala: функции высшего порядка, неявные преобразования (4)

Scala: функции высшего порядка, неявные преобразования

Цели курса

  • Понимать концепцию функций высшего порядка (функции как значения, анонимные функции, замыкания, каррирование)
  • Освоение неявных преобразований и неявных параметров
  • Освойте среду программирования параллелизма Akka

1. Функции высшего порядка

Scala сочетает в себе объектно-ориентированные и функциональные функции. В функциональных языках программирования функции являются «гражданами первого класса». Они находятся на том же уровне, что и другие типы, такие как Int, String и Class, и могут передаваться и передаваться, как и другие типы. переменных.

Функции высшего порядка содержат

  • функционировать как значение
  • анонимная функция
  • Закрытие
  • Карри и др.

1.1 Функции как ценности

В scala функции похожи на числа и строки, и функции можно передавать в метод. Полезно иметь возможность инкапсулировать алгоритмы, а затем передавать определенные действия методам.

Мы изучили метод отображения списка раньше, и он может получить функцию для завершения преобразования списка.

Пример

Пример описания

Преобразует каждый элемент списка целых чисел в соответствующее количество маленьких звездочек.

List(1, 2, 3...) => *, **, *** 

шаг

  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)]

Анализ процесса каррирования

1552811639044

Пример

Пример описания

  • Напишите метод для завершения вычисления двух чисел типа 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 содин параметрМетоды. этоавтоматически вызывается, который автоматически преобразует один тип в другой.

Шаги для использования

  1. Определите метод неявного преобразования в объекте (используя неявный)
  2. Внедрите неявные преобразования (используя импорт) там, где необходимы неявные преобразования.
  3. Автоматически вызывать неявно преобразованный метод

Пример

Пример описания

Используйте неявное преобразование, чтобы File имел функцию чтения, чтобы читать содержимое текста в виде строки.

шаг

  1. Создайте класс RichFile, предоставляющий метод чтения для чтения содержимого файла в виде строки.
  2. Определите метод неявного преобразования для неявного преобразования объекта File в RichFile.
  3. Создайте файл, импортируйте неявное преобразование и вызовите метод чтения файла.

Код ссылки

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 Неявные параметры

Методы могут принимать список параметров, помеченный как неявный. В этом случае компилятор будет искать значение по умолчанию и предоставлять его методу.

определение

  1. Добавьте список параметров после метода, и параметры будут изменены с помощью неявного
  2. Определите неявное значение неявной модификации в объекте
  3. При вызове метода список неявных параметров можно опустить, и компилятор автоматически найдет значение по умолчанию.

[!NOTE]

  1. Как и неявные преобразования, неявные параметры можно импортировать вручную с помощью import
  2. Импортируется автоматически, если в текущей области определено неявное значение.

Пример

Пример описания

  • Определите метод, который включает входящее значение с префиксом и суффиксом разделителя.
  • Разделители определяются с использованием неявных параметров
  • вызовите метод и распечатайте тест

Код ссылки

// 使用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("李雷和韩梅梅"))

}