F# 区分联合 - "downcasting" 到子类型

F# Discriminated Union - "downcasting" to subtype

我真的不知道这个问题的正确标题应该是什么,但是:

我在 F# 中有一个名为 MyDiscriminatedUnion 的受歧视工会:

type MyDiscriminatedUnion =
| Foo of Foo
| Bar of Bar

其中 FooBar 是记录类型:

type Foo = {
   ... }
type Bar = {
   ... }

我创建了联合类型的值Foo:

let foo = Foo {
   ... }

编译器告诉我 foo 的类型是 MyDiscriminatedUnion.

然后我想将 foo 传递给期望类型为 Foo 的函数,而不是 MyDiscriminatedUnion。因此编译器抱怨。我如何告诉编译器 fooFoo 类型?

我试过:

let foo:Foo 

构造联合类型的值时

我尝试通过以下方式"downcast" foo 到 Foo:

foo :?> MyDiscriminatedUnion.Foo

但它们都不起作用。

请帮忙。

Rubber duck debugging 这里的案例...

我需要写一个函数:

let MapToSubtype subtype =
   match subtype with
   | Foo foo -> foo

然后应用函数:

let x = MapToSubtype foo

...并且工作起来很有魅力。

编辑: 请注意,正如 JustSomeFSharpGuy 指出的那样,MapToSubtype 函数并未涵盖所有情况,因此编译器会发出警告,并且可能如果传入 Foo 以外的内容,则给出运行时异常。

所以函数实际上应该是这样的:

let MapToSubtype subtype =
    match subtype with
    | Foo foo -> foo
    | _ -> // deal with exception here

这是来自 OO 语言的常见错误:此代码中不涉及子类型。将联合案例命名为与它们包含的字段类型相同的事实可能会让人感到困惑,所以让我举一个稍微不同的例子:

type MyDiscriminatedUnion =
  | Its_a_Foo of Foo
  | Its_a_Bar of Bar

Its_a_FooIts_a_Bar 不是 子类型,它们是联合案例。 MyDiscriminatedUnion 类型的值要么是 Its_a_Foo,在这种情况下它有一个 Foo 类型的字段,要么是 Its_a_Bar,在这种情况下它有一个类型的字段Bar。要知道是哪一个,得到对应的字段,需要用到模式匹配。

// The function that takes a record of type Foo as argument
let f (x: Foo) = ...

// Our value of type MyDiscriminatedUnion
let myDU = Its_a_Foo { ... }

// Extracting the Foo and passing it to f
match myDU with
| Its_a_Foo foo -> f foo
| Its_a_Bar bar -> // What should we do if it's an Its_a_Bar instead?

// If you're _really_ certain that myDU is Its_a_Foo { ... }, not Its_a_Bar { ... }, you can do this.
// You will get a compile-time warning "FS0025: Incomplete pattern matches on this expression".
// If it's Its_a_Bar, you will get a runtime error.
let (Its_a_Foo foo) = myDU
f foo