是否可以内联使用Type Test Pattern和Record Pattern?
我可以毫无问题地制作记录模式:
let getName3 (a:A) =
match a with
| { name = name } -> name
这是一个完全有效的代码:
type IA =
abstract ID: string
type A =
{ id: string
name: string }
interface IA with
member this.ID = this.id
let getName (a: IA) =
match a with
| :? A as a -> a.name
| _ -> ""
getName
{ id = "1234"
name = "andrew" }
// val getName : a:IA -> string
// val it : string = "andrew"
这就是我在说的:
let getName2 (a: IA) =
match a with
| :? A ({name = name}) as a -> name // Type Test Pattern with Record Pattern inline, maybe even still use binding (as a)
| _ -> ""
更新
我之前的示例太简单了,请改用以下示例:
type IA =
abstract ID: string
type Stage =
| FirstStep
| SecondStep
type A =
{ id: string
name: string option
stage: Stage
}
interface IA with
member this.ID = this.id
// This is a "nested" pattern inline, I match two Option with one match
let tryGetName (a: A option) =
match a with
| Some { name = (Some name) } -> Some name
| _ -> None
// This is a more involved nested pattern inline
let tryGetStageAndName (a: A option) =
match a with
| Some { name = (Some name); stage = stage } -> Some (stage, name)
| _ -> None
// This is the syntax I'm looking for:
let tryGetStageAndName2 (a: IA option) =
match a with
// notice Some (:? A as a) -> is perfectly valid
| Some (:? A ({ name = (Some name); stage = stage }) -> Some (stage, name)
| _ -> None
我也想澄清一下,我的问题是关于F#语法的问题,而不是即席场景或围绕特定type A
的拳击,因为我们可以进行嵌套的内联模式,有没有办法在Type之后做模式测试模式?
答案 0 :(得分:3)
您可以使用活动模式。我们的想法是将类型测试模式转换为其他模式,其中强制转换值将参与其中,因此我们可以将“记录模式”嵌套到其中。
代码为:
let (|IsA|_|) (a: IA) =
match a with
| :? A as a -> Some a
| _ -> None
let getName2 (a: IA) =
match a with
| IsA {name = name} -> name
| _ -> ""
答案 1 :(得分:0)
我认为Nghia Bui提出了一个很好的解决方案。我只是想补充一点,您可能想使活动模式通用,以处理更多情况。我将活动模式的大小写重命名为Unbox
,这可能并不完全准确。无论如何,请参见以下示例:
type IA =
abstract ID: string
type A =
{ id: string
name: string }
interface IA with
member this.ID = this.id
type B =
{ id: string
name: string
email: string }
interface IA with
member this.ID = this.id
let inline (|Unbox|_|)<'T when 'T :> IA> (a: IA) =
match a with
| :? 'T as a -> Some a
| _ -> None
let getName (a: IA) =
match a with
| Unbox {A.name = name} -> name
| Unbox {B.name = name} -> name
| _ -> ""
getName {id = "123"; name = "A name"}
getName {id = "567"; name = "B name"; email = "abc@123.com"}
答案 2 :(得分:0)