Итак, наше путешествие в F # продолжается. Следующая статья будет посвящена типам F #, которые могут иметь или не иметь стандартные эквиваленты .NET. Этот пост о кортежах.
Что такое кортежи
Кортеж — это группа неназванных, но упорядоченных значений, возможно, разных типов.
Создание кортежей
Кортежи очень легко создавать, мы просто делаем что-то вроде показанного ниже. Обратите внимание, как я создал смешанный пакет кортежей, некоторые значения из которых являются числами, а другие являются строками, и мы также можем смешивать и сопоставлять как типы, так и количество значений.
Функции, принимающие кортежи, могут также принимать универсальные кортежи без каких-либо проблем. Система логического вывода типа F # с удовольствием справится с выводом правильных типов для кортежа. Вот пример.
И вот результаты выполнения выше, где можно увидеть, что функция someFunction без проблем принимала и работала с различными типизированными кортежами.

Сигнатуры кортежей
До сих пор мы вообще не касались понимания сигнатур F#, на самом деле это тема, которой я тоже решил посвятить целое сообщение в блоге, так как я считаю, что он достаточна сложна. Однако мы находимся там, где мы есть, то есть здесь и сейчас, и мы изучаем кортежи, поэтому сейчас я просто хотел продемонстрировать, как будет выглядеть сигнатура кортежа.
Допустим, я объявил следующие кортежи в окне FSI:
И затем я рассмотрел их в окне FSI; мы увидим что-то вроде этого:
Это интересно, мы можем увидеть пару вещей здесь, а именно:
Так что кристально чистый кортеж выглядит так:
Будет иметь такую сигнатуру:
Итак, мы увидели, как мы можем создавать кортежи, но как насчет разбивки или деконструкции их обратно в отдельные значения. Это возможно? Да, конечно. Как и прежде, давайте начнем с нескольких примеров:
Результаты печатаются в стандартном окне консоли, следующим образом:

Но как мы получили отдельные части? Ну, все, что вам нужно, в приведенном выше коде, но давайте рассмотрим один пример. Предположим, у нас был такой кортеж:
И я хотел получить значения обоих «значений» кортежа, привязанные к некоторым новым отдельным значениям, мы могли бы просто сделать это:
Мы также можем выбрать только те значения, которые нам действительно нужны, что делается с использованием подстановочного знака для нежелательных частей. Что гарантирует отсутствие ненужного связывания значений. Вот пример:
Также имеется встроенная поддержка для получения первого и второго значений из кортежа. Что можно сделать с помощью функций «fst» и «snd». Нет никакой поддержки для чего-либо, кроме 2-го элемента (это, вероятно, наиболее распространенные случаи). «fst» и «snd» можно использовать следующим образом:
Теперь я хочу обратить ваше внимание на особый случай, когда у нас может быть несоответствие с количеством значений, которые мы пытаемся взорвать на отдельные значения. Так что это будет что-то вроде примера здесь:
Вы можете видеть, что сам кортеж на самом деле содержит 3 значения, но привязка Let имеет только 2 значения, поэтому компилятор предупреждает нас об этом, как вы можете видеть на снимке экрана ниже:

Возможно, вы захотите создать новые кортежи из существующих кортежей, это достаточно просто, вот пример:

Кортежи считаются равными, только если
Давайте посмотрим на какой-нибудь простой пример.

На самом деле, если ваши кортежи имеют разную длину(количество элементов) и вы пытаетесь сравнить их с помощью оператора равенства «=», вы получите предупреждение:

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

Что такое кортежи
Кортеж — это группа неназванных, но упорядоченных значений, возможно, разных типов.
Создание кортежей
Кортежи очень легко создавать, мы просто делаем что-то вроде показанного ниже. Обратите внимание, как я создал смешанный пакет кортежей, некоторые значения из которых являются числами, а другие являются строками, и мы также можем смешивать и сопоставлять как типы, так и количество значений.
let a = (1,2) let b = (1,"cat") let c = (1,"cat") let d = (1,"cat", 'c')
Универсальные кортежи
Функции, принимающие кортежи, могут также принимать универсальные кортежи без каких-либо проблем. Система логического вывода типа F # с удовольствием справится с выводом правильных типов для кортежа. Вот пример.
let someFunction tup = let (x,y) = tup printfn "x is %A and y is %A" x y do someFunction ("cat","dog") do someFunction (11,12)
И вот результаты выполнения выше, где можно увидеть, что функция someFunction без проблем принимала и работала с различными типизированными кортежами.

Сигнатуры кортежей
До сих пор мы вообще не касались понимания сигнатур F#, на самом деле это тема, которой я тоже решил посвятить целое сообщение в блоге, так как я считаю, что он достаточна сложна. Однако мы находимся там, где мы есть, то есть здесь и сейчас, и мы изучаем кортежи, поэтому сейчас я просто хотел продемонстрировать, как будет выглядеть сигнатура кортежа.
Допустим, я объявил следующие кортежи в окне FSI:
let a = (1,2) let b = (1,"codfather") let c = (1,"c", 12.5)
И затем я рассмотрел их в окне FSI; мы увидим что-то вроде этого:
val a : int * int = (1, 2) val b : int * string = (1, "codfather") val c : int * string * float = (1, "c", 12.5)
Это интересно, мы можем увидеть пару вещей здесь, а именно:
- Круглые скобки не являются частью сигнатуры типа
- Система типов F# может правильно выводить тип на основе значений, содержащихся в самом кортеже.
- Запятая заменяется на «*»
Так что кристально чистый кортеж выглядит так:
let a = (1,2)
Будет иметь такую сигнатуру:
int * int
Разбивка кортежей
Итак, мы увидели, как мы можем создавать кортежи, но как насчет разбивки или деконструкции их обратно в отдельные значения. Это возможно? Да, конечно. Как и прежде, давайте начнем с нескольких примеров:
let (a,b) = (1,2) printfn "(a,b) = (1,2), so value of 'a' should be 1, and it is =%i,\r\n 'b' should be 2, and it is =%i" a b // используя подстановочный знак, по сути, не создавайте ненужную привязку значения, если вы // не заинтересован в этом let (_,z) = (1,2) printfn "grabbing last value from (1,2) which is = %i" z let (a,b :string) = (1,"cat") printfn "grabbing (1,\"cat\") which has values = %i %s" a b let (a :int,b :string) = (1,"cat") printfn "grabbing (1,\"cat\") which has values = %i %s" a b let (a ,b, c) = (1,"cat", 'c') printfn "grabbing (1,\"cat\",'c') which has values = %i %s %c" a b c let first = fst (1, 2) printfn "grabbing fst from (1,2) which has values = %i" first let second = snd (1, 2) printfn "grabbing 2nd from (1,2) which has values = %i" second
Результаты печатаются в стандартном окне консоли, следующим образом:

Используя Let
Но как мы получили отдельные части? Ну, все, что вам нужно, в приведенном выше коде, но давайте рассмотрим один пример. Предположим, у нас был такой кортеж:
(1,2)
И я хотел получить значения обоих «значений» кортежа, привязанные к некоторым новым отдельным значениям, мы могли бы просто сделать это:
let (a,b) = (1,2)
Мы также можем выбрать только те значения, которые нам действительно нужны, что делается с использованием подстановочного знака для нежелательных частей. Что гарантирует отсутствие ненужного связывания значений. Вот пример:
let (_,z) = (1,2)
Использование встроенных функций кортежа
Также имеется встроенная поддержка для получения первого и второго значений из кортежа. Что можно сделать с помощью функций «fst» и «snd». Нет никакой поддержки для чего-либо, кроме 2-го элемента (это, вероятно, наиболее распространенные случаи). «fst» и «snd» можно использовать следующим образом:
let first = fst (1, 2) let second = snd (1, 2)
Теперь я хочу обратить ваше внимание на особый случай, когда у нас может быть несоответствие с количеством значений, которые мы пытаемся взорвать на отдельные значения. Так что это будет что-то вроде примера здесь:
let (a ,b) = (1,"cat", 'c')
Вы можете видеть, что сам кортеж на самом деле содержит 3 значения, но привязка Let имеет только 2 значения, поэтому компилятор предупреждает нас об этом, как вы можете видеть на снимке экрана ниже:

Создание новых кортежей
Возможно, вы захотите создать новые кортежи из существующих кортежей, это достаточно просто, вот пример:
let oldOne = (1,2) let (x,y) = oldOne let newOne = (x+1,y+1) printfn "original = %A, and we did this (x+1,y+1)\r\n to obtain newOne = %A" oldOne newOne

Сравнение кортежей
Кортежи считаются равными, только если
- Они имеют одинаковое количество значений
- ВСЕ значения считаются равными (очевидно, это могут быть пользовательские методы Equals или пользовательские реализации IEquatable и тому подобное)
Давайте посмотрим на какой-нибудь простой пример.
printfn "(1,2) = (3,4) =% b" ((1,2) = (3,4)) printfn "(1,2) = (1,2) =% b" ((1,2) = (1,2)) printfn "('a', 'b') = ('a', 'b') =% b" (('a', 'b') = ('a', 'b')) printfn "('a', 'b') = ('a', 'c') =% b" (('a', 'b') = ('a', 'c'))

На самом деле, если ваши кортежи имеют разную длину(количество элементов) и вы пытаетесь сравнить их с помощью оператора равенства «=», вы получите предупреждение:

Паттерны сопоставления кортежей
Мы еще не занимались паттернами сопоставления, но позже увидим целый пост на эту тему. А пока просто знайте, что это способ снова сопоставить входные параметры. Вы можете сделать это для кортежей, что делается следующим образом:
let someFunction tup = match tup with | 1,2 -> printfn "you passed (1,2)" | _,_ -> printfn "you passed some other tuple" do someFunction (11,12) do someFunction (4,5) do someFunction (1,2) do someFunction (13,23)

