Print case-идентификатор дискриминируемого объединения
У меня есть Option
Тип:
type Option<'a> =
| Some of 'a
| None
override x.ToString() = sprintf "%A" x
printf "%A" None // "None"
printf "%A" (Some 1) // "Some 1"
Предположительно, в функции я хочу напечатать Some 1
, но в другой функции я хочу напечатать ее case-идентификатор, т. е. Some
(отбросьте значение "1"). Как я могу это сделать?
3 ответа:
Если вы хотите сделать это универсальным способом, а не реализовывать член для каждого из ваших типов, вы можете использовать отражение для этого:
open Microsoft.FSharp.Reflection let caseLabel<'t> (x: 't) = let typ = typeof<'t> if FSharpType.IsUnion(typ) then let case, _ = FSharpValue.GetUnionFields(x, typ) Some case.Name else None
Можно использовать спичку:
override x.ToString() = match x with | Some _ -> "Some" | None -> "None"
Чтобы ответить на ваш комментарий: В этом случае я бы не переопределял метод ToString, а вместо этого делал отдельные совпадения в зависимости от предполагаемого поведения. Или просто определите вспомогательную функцию для печати опции без указания содержимого;
Таким образом, вы можете либо использоватьlet printEmpty myOpt = match myOpt with | Some _ -> "Some" | None -> "None"
sprintf "%A" myOpt
для печати с содержимым, либоprintEmpty myOpt
для печати без него.
Для чего бы это ни стоило, я включаю версию @scrwtp с формой "расширение типа", а не оригинальное переосмысление опции. Причина заключается просто в том, что самый последний определенный тип перепутал использование caseLabel в части ToString (определения типа Option в исходном вопросе).
NB. поскольку мы не можем наследовать от DU (у него нет конструкторов), мы не можем перегружать ToString. Поэтому наращивание с помощью метода toString еще по умолчанию в оригинальной Метод toString. Поэтому стиль статического модуля, вероятно, более желателен, поскольку мы можем явно получить доступ к новому поведению. В противном случае поведение sprintf / printf будет обращаться к исходной строке ToString, а это не то, что мы хотим в соответствии с вопросом. Я считаю это ошибкой компилятора. Ошибка подана над здесь
Кстати: fsi pretty printing может облегчить это для сценариев только для FSI (TBD).
open Microsoft.FSharp.Reflection let caseLabel (x:'x) = typeof<'x> |> fun typ -> if FSharpType.IsUnion(typ) then FSharpValue.GetUnionFields(x, typ) ||> fun case _ -> Some(case.Name) else None type Option<'t> with static member toString x = match caseLabel x with | Some(label) -> label | None -> "None" sprintf "%s" <| (Some 1 |> Option.toString) // returns "Some" sprintf "%s" <| (None |> Option.toString) // returns "None"