F# Discriminated Union - “downcasting” to subtype

≯℡__Kan透↙ 提交于 2019-12-05 18:03:17

This is a common mistake when coming from an OO language: there are no subtypes involved in this code. The fact that you named your union cases the same as the type of the field they contain can make this confusing though, so let me give a slightly different example:

type MyDiscriminatedUnion =
  | Its_a_Foo of Foo
  | Its_a_Bar of Bar

Its_a_Foo and Its_a_Bar are not subtypes, they're union cases. A value of type MyDiscriminatedUnion is either an Its_a_Foo, in which case it has a field of type Foo, or an Its_a_Bar, in which case it has a field of type Bar. To know which one it is and get the corresponding field, you need to use pattern matching.

// 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
Marta

Rubber duck debugging case here...

I needed to write a function:

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

Then apply the function:

let x = MapToSubtype foo

... and worked like a charm.

Edit: Please note that as JustSomeFSharpGuy pointed out the MapToSubtype function doesn't cover all cases so the compiler will give a warning and could give a runtime exception if something else than Foo is passed in.

So the function should really look like this:

let MapToSubtype subtype =
    match subtype with
    | Foo foo -> foo
    | _ -> // deal with exception here
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!