Член Enum (флаги) состоит из других членов

[<Flags>]
type LikeMatch =
    | None  = 0
    | Start = 1
    | End   = 2
    | All   = Start ||| End //ERROR: Unexpected identifier in union case

Я также пытался квалифицировать участников с типом enum. Есть ли способ сделать это в F#?

3 ответа

Решение

Согласно справочнику по языку F#, сделать это невозможно. Правая часть знака = в перечислении F# должна быть целочисленным литералом

грамматика

type enum-name =
   | value1 = integer-literal1
   | value2 = integer-literal2

Как говорит JaredPar, это не разрешено языком, но F# имеет двоичные литералы, которые позволяют легко показать, какие биты устанавливаются:

open System

[<Flags>]
type LikeMatch =
    | None  = 0b000000000
    | Start = 0b000000001
    | End   = 0b000000010
    | All   = 0b000000011

Мы можем определить комбинации флагов:

  1. Встроенный - см . ответ Роберта
  2. В сопутствующем модуле

Каждый вариант имеет свои плюсы и минусы.

1. Встроенные комбинации вручную

      [<System.Flags>]
type LikeMatch =
    | None  = 0b00
    | Start = 0b01
    | End   = 0b10
    | All   = 0b11 // ❌ Not human-friendly (more difficult to understand it's "Start + End")

let all = LikeMatch.All
// val all: LikeMatch = All

let all' = LikeMatch.Start ||| LikeMatch.End
// val all': LikeMatch = All
// ✔️ Compiler-friendly

2. В сопутствующем модуле

      [<System.Flags>]
type Spacing =
    | Left   = 0b0001
    | Right  = 0b0010
    | Top    = 0b0100
    | Bottom = 0b1000

[<RequireQualifiedAccess>]
module Spacing =
    let Horizontal = Spacing.Left ||| Spacing.Right  // ✔️ Human-friendly
    let Vertical = Spacing.Top ||| Spacing.Bottom
    let All = Horizontal ||| Vertical

let horizontal = Spacing.Horizontal
// val horizontal: Spacing = Left, Right
// ❌ Not "Horizontal"

Также есть разница относительно HasFlag, включены комбинации или нет:

      [<RequireQualifiedAccess>]
module Enum =
    let values<'enum when 'enum :> System.Enum> =
        System.Enum.GetValues(typeof<'enum>)
        :?> 'enum array
        |> Array.toList

    let flags<'enum when 'enum :> System.Enum> (enumValue: 'enum) =
        values<'enum>
        |> List.filter (enumValue.HasFlag)

let flagsInline = Enum.flags LikeMatch.All
// val flagsInline: LikeMatch list = [None; Start; End; All]
// ⚠️ Includes "None" and "All"

let flagsCompanion = Enum.flags Spacing.All
// val flagsCompanion: Spacing list = [Left; Right; Top; Bottom]
//  Only includes core flags
Другие вопросы по тегам