F # Записи с членами против классов - PullRequest
2 голосов
/ 25 апреля 2019

В F # вы можете определять записи с помощью функций-членов, а также создавать классы.

type Album = {
    Id: int
    Name: string
    DateReleased: DateTime
    Genre: Genre }
with
    member this.PrintMessage() =
        printf "Hello from %s\n" this.Name

, поэтому используется

let first = 
        { Id = 1; 
          Name = "Hello World!"
          Genre = KPop;
          DateReleased = DateTime(1991, 8, 12) }
first.PrintMessage()

, а с классами это может быть что-то вроде этого.

type Album(
     Id: int, 
     Name: string, 
     DateReleased: DateTime, 
     Genre: Genre ) as me =
     do
         me.PrintMessage()
     member this.PrintMessage() =
         printf "Hello %s" Name

Когда удобно использовать один или другой?Может ли моделирование предметной области выполняться только с записями?

Может ли класс быть преобразован в запись и наоборот с помощью некоторого скрытого кастинга FSharp?

Ответы [ 3 ]

5 голосов
/ 25 апреля 2019

Моделирование домена может быть выполнено как с записями, так и с классами.Я думаю, когда использовать один или другой вопрос, прежде всего, вопрос предпочтений и окружающей среды.Лично я обычно не использую классы, однако я знаю некоторых людей, которые используют их довольно часто.Классы больше полагаются на мутации и более производительны за счет простоты использования.Лично я считаю, что если вы собираетесь писать объектно-ориентированный стиль, используйте классы, а если вы пишете функциональный стиль, используйте записи.Записывает паттерны, сопоставляет и разбирает проще.Часть этого различия культурная, просто потому, что вы можете делать что-то определенным образом, не означает, что другие люди смогут легко вас понять.Код написан для чтения, как вами, так и другими.Когда вы выбираете записи или классы, они сообщают о стиле и использовании этих типов.Наконец, я не знаю, что класс может быть преобразован в запись в F #, и если бы это было возможно, я бы по-прежнему рекомендовал это делать.Это связано с тем, что использование записей в качестве классов и классов в качестве записей противоречит культурным нормам вокруг этих конструкций.Я лично думаю, что ваш пример член подходит как для записей, так и для занятий.Я обычно люблю использовать модули с одинаковыми именами для функций, связанных с данным типом, потому что это может сделать его менее запутанным, когда функция потребляет что-то другое, чем тип записи.Однако я не думаю, что кто-либо хорошо воспитанный будет противиться любому из ваших примеров кода там.

type Album(
    Id: int, 
    Name: string, 
    DateReleased: string, 
    Genre: int ) as me =
    let mutable genre = Genre  
    //readonly property
    member val Id = Id
    //autoproperty with get and set
    member val Name = Name with get, set
    member val DateReleased = DateReleased with get, set
    //property with explicit get and set
    member this.Genre 
        with get () = genre
        and set (value) = genre <- value

см. Когда мне следует использовать let, member val и member this.?

1 голос
/ 25 апреля 2019

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

Если ваш сценарий использования позволяет, вы также можете использовать поля CLI с определениями F # mutable val.С другой стороны, аналогичное, доступное только для чтения определение val также предоставляется средством получения свойства.

type Album =
    // CLI property getter
    val Id : int
    // mutable CLI field
    [<DefaultValue>]
    val mutable Name : string
    // non-primary constructor with sequence construction (before)
    new (id: int, name : string) as me =
         { Id = id } then me.Name <- name

Существуют недостатки:

  • отсутствие основного конструктора,
  • громкость дополнительного выражения конструктора,
  • , обеспечивающая инициализацию по умолчанию для типа поля, с DefaultValueAttribute

И это может считаться недиоматическим.

0 голосов
/ 29 апреля 2019

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

type Album = {
    Id: int
    Name: string
    DateReleased: DateTime
    Genre: Genre
}
module Album =
    let printMessage album =
        printfn "Hello from %s" album.Name

let first = {
    Id = 1
    Name = "Hello World!"
    Genre = KPop
    DateReleased = DateTime(1991, 8, 12)
}
Album.printMessage first
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...