F#被歧视的联盟 - "向下倾斜"到子类型

时间:2015-06-15 09:19:22

标签: f# discriminated-union

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

我在MyDiscriminatedUnion中有一个名为F#的歧视联盟:

type MyDiscriminatedUnion =
| Foo of Foo
| Bar of Bar

其中FooBar是记录类型:

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

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

let foo = Foo {
   ... }

编译器告诉我foo的类型为MyDiscriminatedUnion

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

我试过了:

let foo:Foo 

构造union类型的值时。

我试过" downcast" foo to Foo by:

foo :?> MyDiscriminatedUnion.Foo

但它们都不起作用。

请帮忙。

2 个答案:

答案 0 :(得分:10)

这是来自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. If it's Its_a_Bar, you will get a runtime error.
let (Its_a_Foo foo) = myDU
f foo

答案 1 :(得分:0)

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