针对字符串的模式匹配 属性

Pattern matching against a string property

我正在反序列化来自 JSON 的一些映射,稍后我需要基于反序列化类型的 string 字段进行模式匹配,如下所示:

let mappings = getWorkItemMappings

let result =
  workItemMappings
  |> Seq.find (fun (m: WorkItemMapping) -> m.Uuid = workTime.workItemUuid)

  match mapping.Name with

即使我完成所有情况的模式匹配,我仍然得到 Incomplete pattern matches on this expression.。由于 Name 字段的字符串类型,这对我来说很明显。

有没有办法告诉编译器 Name 字段的哪些值可用?

我想我可以为可能的映射类型创建一个联合类型,并尝试将 JSON 反序列化为这个联合类型,但如果还有其他选择,我想这样做。

很难理解你在问什么。也许这个片段可以提供帮助。它演示了如何在模式匹配中使用文字字符串常量,以及如何在函数中重用。这在添加和删除案例时增加了一些安全性和可读性。如果您不希望直接序列化 DU,那么这作为解决方案的一部分可能很有用。

type MyDu =
    | A
    | B
    | C

let [<Literal>] A' = "A"
let [<Literal>] B' = "B"
let [<Literal>] C' = "C"

let strToMyDuOption (s: string) =
    match s with
    | A' -> Some A
    | B' -> Some B
    | C'-> Some C
    | _ -> None
    
let strToMyDu (s: string) =
    match s with
    | A' -> A
    | B' -> B
    | C'-> C
    | s -> failwith $"MyDu case {s} is unknown."

let myDuToStr (x: MyDu) =
    match x with
    | A -> A'
    | B -> B'
    | C -> C'

// LINQPad
let dump x = x.Dump()

strToMyDuOption A' |> dump
strToMyDuOption "x" |> dump

myDuToStr A |> dump

如果您在字符串值上进行模式匹配,编译器无法静态保证它只会有特定值,因为构造不同值的字符串总是可能的。它来自 JSON 的事实并没有帮助 - 你可能总是有一个无效的 JSON.

最好的选择是添加一个引发自定义描述性异常的默认案例。您在其他地方处理的任何一个(表明 JSON 文件无效)或(如果您在其他地方检查有效性)像这样:

let parseFood f = 
  match f with
  | "burger" -> 1
  | "pizza" -> 2
  | _ -> raise(invalidArg "f" $"Expected burger or pizza but got {f}")

请注意,F# 编译器非常 谨慎。它甚至不允许您使用模式匹配来处理枚举值,因为在幕后,有一些方法可以创建无效的枚举值!例如:

type Foo = 
  | A = 1

let f (a:Foo) = 
  match a with 
  | Foo.A -> 0

warning FS0104: Enums may take values outside known cases. For example, the value 'enum (0)' may indicate a case not covered by the pattern(s).