Предостережения о возвращении анонимных записей вместо кортежей - PullRequest
0 голосов
/ 22 января 2019

Рассмотрим следующую (общую, может быть общедоступную в библиотеке) служебную функцию для анализа строки как учетных данных HTTP Basic и возврата имени пользователя и пароля:

let parseBasicCredentials (encodedCredentials: string) =
  (* approx. 10 lines of pipes, matching and try/with *)
  username, password

Поскольку имя пользователя и пароль являются строками, вызывающие абоненты должны помнить (или проверять документы), что имя пользователя возвращается в качестве первого элемента кортежа, а пароль - в качестве второго.

Однако F # скоро получит поддержку анонимных записей (уже доступно в ночных клубах). Когда это происходит, такие функции также могут возвращать анонимную запись:

let parseBasicCredentials (encodedCredentials: string) =
  (* approx. 10 lines of pipes, matching and try/with *)
  {| Username = username; Password = password |}

Кажется, это работает нормально, но, поскольку это совершенно новая языковая функция, я не уверен, есть ли в этом какие-либо недостатки, будь то технические или просто неодобрительные. AFAIK, возвращающий кортеж, является идиоматическим и приемлемым решением для простых вспомогательных функций, таких как эта. Кроме того, анонимный тип позволяет присваивать имена элементам и, таким образом, его можно считать более «безопасным», поскольку он более самодокументирован и, следовательно, лучше предотвращает перепутывание возвращаемым значением вызывающей стороны.

Я не рассматриваю вспомогательные функции общего назначения (не доменные), такие как эти кандидаты для возврата отдельно определенных типов записей или кортежей единичных DU. Мне только любопытно, теперь, когда существуют анонимные записи, могут ли они служить «лучшими кортежами», когда нужны специальные, не примитивные возвращаемые значения, как здесь, или если кортежи как-то все еще предпочтительны (и, если да, для которых причины).

1 Ответ

0 голосов
/ 22 января 2019

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

Они будут более полезны в качестве удобного способа хранения переходных данных вфункция или файл сценария.

Исправление:

Их можно использовать в качестве входных данных.Вот пример:

let showCredentials (x:{| Username:string; Password:string |}) =
    printfn "Username: %s, Password %s" x.Username x.Password

Однако вы должны указать все поля в записи, чтобы он соответствовал типу.Поэтому, чтобы написать другую функцию, которая принимает тот же тип, но не использует пароль, вы должны написать следующее:

let showUsername (x:{| Username:string; Password:_ |}) =
    printfn "Username: %s" x.Username

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

Вполне возможно, что сопоставление с образцом будет добавлено, так что вы могли бы вместо этого написать:

let showUsername {| Username = username |} =
    printfn "Username: %s" username

Но мне не ясно, будет ли это происходитьбыть добавленным к языку.

...