如何使用Option.map做空条件? F#如何获取空对象的属性?虫子?

时间:2018-08-21 19:36:28

标签: f#

以下代码返回conformed_name = "MISCELLANEOUS SUBJECT CORP" CIK = "000000000" IRS_number = "123456789" fiscal_year_end = "1231" 而不是Some "Test"。基本上,我正在尝试实现None的C#代码。

cObj?.B.A.P

在Option.map中,似乎F#不会将// Setup [<AllowNullLiteral>] type A() = member x.P = "Test" [<AllowNullLiteral>] type B(a:A) = member x.A = a [<AllowNullLiteral>] type C(b:B) = member x.B = b // Test let aObj: A = null let cObj = new C(new B(aObj)) let r = cObj |> Option.ofObj |> Option.map(fun c -> c.B) |> Option.map(fun b -> b.A) |> Option.map(fun a -> a.P) // Expect return None since a is null // printfn "%A" a; will print <null>. // How can F# got property of null object? r 视为null。是否有一个简单的解决方法,使它在找到None后立即返回None?

2 个答案:

答案 0 :(得分:5)

与C#不同,F#试图在任何地方都显式。从长远来看,这将导致程序更加可维护和正确。

特别是,nullOption毫无关系。 nullNone不同。 None是类型Option的值,而null是一个非常模糊的概念-值可以是任何类型。

如果您想在参数为None时返回null,否则返回Some,则您需要的是Option.bind,而不是Option.mapOption.bind采用一个函数,该函数采用一个值(从前一个Option中提取),并返回另一个Option。像这样:

let maybeC = Option.ofObj cObj
let maybeB = maybeC |> Option.bind (c -> Option.ofObj c.B)
let maybeA = maybeB |> Option.bind (b -> Option.ofObj b.A)
let maybeP = maybeA |> Option.bind (a -> Option.ofObj a.P)

或一口气:

let maybeP = 
    Option.ofObj cObj
    |> Option.bind (c -> Option.ofObj c.B)
    |> Option.bind (b -> Option.ofObj b.A)
    |> Option.bind (a -> Option.ofObj a.P)

如果您经常执行此类操作,则可以组合Option.bindOption.ofObj调用并将其编码为单独的函数:

let maybeNull f = Option.bind (x -> Option.ofObj (f x))

let maybeP =
    Option.ofObj cObj
    |> maybeNull (c -> c.B)
    |> maybeNull (b -> b.A)
    |> maybeNull (a -> a.P)

但是,如果您发现自己陷入null之类的情况,我建议也许您的域设计没有被很好地考虑。空值不是一个好的建模工具,应尽可能避免使用它们。我鼓励您重新考虑您的设计。

答案 1 :(得分:0)

Option.map的第一个参数是函数'T -> 'U。其参数的类型为'T,而不是'T option。因此,在您的最后一个lambda fun a -> a.P中,null参数表示类型为A的null,而不是类型为A option的null。

因为类型P的成员A仅返回字符串“ Test”,所以即使接收者为null,调用也会成功并返回。如果尝试在P的正文中使用self标识符,则将获得null引用异常。