Pull to refresh

F#4: Let / Use / Do

Reading time 3 min
Views 2.1K
Original author: Sacha Barber
В этом посте мы рассмотрим привязки в F#, в частности мы рассмотрим Let / Use / Do. Теперь вы, возможно, спрашиваете себя, что такое привязки, и, поскольку мы еще не рассмотрели их, сейчас самое время поговорить об этом.

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

Let


Вы используете ключевое слово let, чтобы связать имя со значением или функцией. На самом деле есть тонкое различное использование Let, где один объявлен на верхнем уровне в модуле, а затем другой, где мы определяем некоторый локальный контекст. Вот пример обоих из них:

module DemoModule =
 
    let someFunction =
        let a = 1
        let b = 2
        a * b

Мы могли бы получить доступ к someFunction, используя полностью определенное имя, такое как DemoModule.someFunction, но вложенные привязки Let (a, b) доступны только для Let верхнего уровня. Обычно вы видите больше случаев, когда мы используем привязку Let для объявления некоторых значений внутреннего модуля, поэтому давайте сконцентрируем свои усилия там (хотя важно знать, что вы можете использовать Let на уровне модуля).

Итак, давайте посмотрим на еще несколько примеров

let aString ="this is a string"
let aInt = 12
let aDecimal = 12.444
let aPiFunction () = Math.PI
let aSquareRootFunction (x) = Math.Sqrt(x)
let aFullyTypedSquareRootFunction (x :float) = Math.Sqrt(x)
let a,b = "a","tuple"

Можно видеть, что мы можем использовать привязку Let для привязки к многочисленным значениям, которые могут быть различных типов, таких как:

  • Целое число
  • Десятичное число
  • Функция без входных параметров
  • Функция с входными параметрами (где система логического вывода типа F # будет правильно выбирать тип)
  • Функция, которая имеет полностью определенные типы параметров
  • Кортеж (в этом случае кортеж String * String)

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

Вы можете прочитать больше о привязке Let на MSDN

Use


Привязка Use очень похожа на привязку Let, поскольку она привязывает значение к результату выражения. Основное отличие состоит в том, что привязка Использования предназначена для работы с типами IDisposable и автоматически удаляет значение, когда оно больше не находится в области видимости. Это очень похоже на ключевое слово .NET using, хотя я не верю, что привязка F# Use будет точно такой же, как и using в .NET, поскольку ключевое слово using в .NET на самом деле представляет собой try/finally с вызовом Dispose() в finally.

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

use sw = new StreamWriter(@"c:\temp\fprintfFile.txt")
fprintf sw "This is a string line %s\r\n" "cat"
fprintf sw "This is a int line %i" 10
sw.Close()

В этом примере привязка Use гарантирует, что метод StreamWriter будет вызывать свой метод Dispose() после вызова sw.Close(), показанного выше.

Use только работает с IDisposables, и вы получите ошибку компиляции, если вы попытаетесь использовать его с чем-то еще, как показано ниже:

image

Так как метод Dispose () вызывается в конце привязки Use, следует позаботиться о том, чтобы не возвращать значение, которое было связано с помощью Let.

let Write =
    use sw = new StreamWriter(@"c:\temp\fprintfFile.txt")
    sw

Если вам абсолютно необходимо передать IDisposable обратно, который являются частью привязки Use, вы можете вместо этого использовать обратный вызов. Что-то вроде этого будет работать, но я бы остановился и спросил себя, правильно ли вы разработали свой дизайн, если вы делаете такие вещи:

let Write callback =
    use sw = new StreamWriter(@"c:\temp\fprintfFile.txt")
    fprintf sw "Write is writing to the StreamWriter"
    callback sw
    sw
 
let callback sw = fprintf sw "sw is the StreamWriter"
let disp = Write callback

Do


Привязка do используется для выполнения кода без определения функции или значения. A Привязка ДОЛЖНА всегда возвращать Unit (без значения / пустота). Во многих случаях вы сможете опустить привязку Do, и все будет работать так, как ожидалось.

Вот несколько примеров использования привязки Do.

do printf "doing the do"
//oh oh not a unit
do printf "print a sum %i" 1 + 1
do 1 + 1

Если я вместо этого покажу вам снимок экрана с кодом выше, вы увидите, что компилятор будет жаловаться, если вы попробуете использовать Do с результатом не-Unit.

image

У Вас есть два варианта:

  • Использовать конвейерный оператор, чтобы игнорировать результат
  • Создать привязку let

Я показал пример каждого из них ниже:

let x = 1 + 1
do printf "print a sum %i" x
do (1+1 |> ignore)

Let! Use! Do!


Хотя я пока не хочу их обсуждать, иногда вы можете случайно увидеть Let! Use! Do!, и когда вы делаете это, это часть того, что называется вычислительным выражением. Скорее всего, вы увидите это в асинхронных рабочих процессах F#, которые мы рассмотрим в одной из заключительных статей. Если я достаточно разбираюсь, я могу даже попытаться объяснить, как вы можете создать свое собственное «Вычислительное выражение», хотя они представляют собой довольно абстрактную концепцию и довольно сложную тему, поэтому сейчас не время для них.
Tags:
Hubs:
+10
Comments 0
Comments Leave a comment

Articles