Первый пример не ориентирован на многопотоковое исполнение - если два потока называют getInstance одновременно, который статичный будет ЛАВАШЕМ. Некоторая форма взаимного исключения помогла бы.
Версия соответствия называется "выражением сопоставления с образцом". Версия функции называется «функцией сопоставления с образцом». Найдено в разделе 6.6.4 спецификации .
Использование одного над другим - вопрос стиля. Я предпочитаю использовать только версию функции, когда мне нужно определить функцию, которая является только оператором соответствия.
Плюс второго синтаксиса в том, что при использовании в лямбде он может быть немного более кратким и читаемым.
List.map (fun x -> match x with | 1 -> "one" | _ -> "not one") [0;1;2;3;1]
vs
List.map (function 1 -> "one" | _ -> "not one") [0;1;2;3;1]
В вашем случае они делают то же самое - ключевое слово function
действует как комбинация ключевого слова fun
(для создания анонимной лямбды) за которым следует ключевое слово match
.
Таким образом, технически это одно и то же, с добавлением забавы
:
let foo1 = fun x ->
match x with
| 1 -> "one"
| _ -> "not one"
let foo2 = function
| 1 -> "one"
| _ -> "not one"
Версия функции - это сокращение от синтаксиса полного соответствия в особом случае, когда оператор соответствия представляет собой всю функцию, а функция имеет только один аргумент (кортежи считаются как один). Если вы хотите иметь два аргумента, вам нужно использовать синтаксис полного соответствия *. Вы можете увидеть это в типах следующих двух функций.
//val match_test : string -> string -> string
let match_test x y = match x, y with
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
//val function_test : string * string -> string
let function_test = function
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
Как вы можете видеть, версия соответствия принимает два отдельных аргумента, тогда как версия функции принимает один кортежный аргумент. Я использую версию функции для большинства функций с одним аргументом, так как считаю, что синтаксис функции выглядит чище.
* Если вы действительно хотите, вы можете получить версию функции с правильной сигнатурой типа, но, на мой взгляд, это выглядит довольно некрасиво - см. пример ниже.
//val function_match_equivalent : string -> string -> string
let function_match_equivalent x y = (x, y) |> function
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
два синтаксиса эквивалентны. Большинство программистов выбирают один или другой, а затем используют его последовательно.
Первый синтаксис остается более читаемым, когда функция принимает несколько аргументов перед началом работы.
Для полноты картины я только что перешел на страницу 321 из Expert FSharp :
"Примечание, листинг 12-2 использует форму выражения
function pattern-rules -> expression
. Это эквивалентно(fun x -> match x with pattern-rules -> expression)
и особенно удобно как способ определения функций, работающих непосредственно над размеченными объединениями. "