F# |如何在 Match 表达式中管理 null(不可为 Nullable)?
F# | How to manage null (not Nullable) in a Match expression?
open System.Linq
type Car(model:string, color:string) =
member this.Model = model
member this.Color = color
member this.ToString() = sprintf "ModeL:%s Color:%s" model color
let cars = [
Car("Ferrari", "red")
Car("BMW", "blu")
]
let getCar model =
match cars.FirstOrDefault(fun c -> c.Model = model) with
| car -> Some(car) // matches ALWAYS !
//| car when car <> null -> Some(car)
//| car when car <> (default(Object)) -> Some(car)
//| null -> None
//| Null -> None
let mercedes = getCar("Mercedes")
let car = match mercedes with
| Some c -> c.ToString() // c is null !!!
| _ -> "not found"
FirstOrDefault
不是 return Nullabe,所以我无法匹配 null
。
那么,如何检查匹配表达式中函数的 null
return?
我正在使用 FirstOrDefault,因为我尝试使用 Enumerable 中最简单的对象 (Seq)。
我知道我可以使用从 Enumerable 开始的其他东西,但我仍然想了解我在这里缺少的东西。
[解决方案]
感谢@Abel 建议使用 .tryFind()
我完成了任务
Seq.tryFind()
return 是 Car option
。
let getCar model =
let cars = lazy(
// this.Collection.Indexes.List().ToEnumerable() // this is the real data I'm using (MongoDB indexes of a collection)
// |> Seq.map parseIndex // a function that create Car (Index) from the BsonDocumentBsonDocument
cars.AsEnumerable()
)
cars.Value |> Seq.tryFind(fun c -> c.Model = model)
let mercedes = match getCar("Mercedes") with
| Some c -> c.ToString()
| _ -> "not found"
let ferrari = match getCar("Ferrari") with
| Some c -> c.ToString()
| _ -> "not found"
F# 中的 类 不能将 null
作为适当的值(这是 F# 更强大的方面之一)。但是,您可以通过添加 AllowNullLiteral
属性来打破此约定:
[<AllowNullLiteral>]
type Car(model:string, color:string) =
member this.Model = model
member this.Color = color
现在您可以创建 null
的实例,当您需要与可以 return null
的代码互操作时,在代码中使用它会更容易。 =27=]
请注意,带有 | car ->
的代码是一个变量模式,这意味着它捕获所有内容并将值分配给变量 car
。不确定你想在这里做什么,但是 类 上的模式匹配不是很有用。
如果您需要匹配 null
,将其作为第一个匹配项,第二个匹配项可以是 car
,捕获其他所有内容。您的代码将变为:
[<AllowNullLiteral>]
type Car(model:string, color:string) =
member this.Model = model
member this.Color = color
member this.ToString() = sprintf "ModeL:%s Color:%s" model color
module X =
let cars = [
Car("Ferrari", "red")
Car("BMW", "blu")
]
let getCar model =
match cars.FirstOrDefault(fun c -> c.Model = model) with
| null -> None
| car -> Some(car) // matches everything else
关于您的代码的另一个注意事项:Car
类型也可以作为记录创建:
type Car =
{
Model: string
Color: string
}
而不是使用 LINQ,使用 List.tryFind
(或者 Seq.tryFind
,如果你想使用 IEnumerable
)更惯用,它会自动 return 是一个选项,您不必在 F# 代码中突然引入 null
。您的代码总体上会变得更简单:
type Car =
{
Model: string
Color: string
}
override this.ToString() = sprintf "ModeL:%s Color:%s" this.Model this.Color
module X =
let cars = [
{ Model = "Ferrari"; Color = "red" }
{ Model = "BMW"; Color = "blu" }
]
let getCar model = cars |> List.tryFind (fun x -> x.Model = model)
open System.Linq
type Car(model:string, color:string) =
member this.Model = model
member this.Color = color
member this.ToString() = sprintf "ModeL:%s Color:%s" model color
let cars = [
Car("Ferrari", "red")
Car("BMW", "blu")
]
let getCar model =
match cars.FirstOrDefault(fun c -> c.Model = model) with
| car -> Some(car) // matches ALWAYS !
//| car when car <> null -> Some(car)
//| car when car <> (default(Object)) -> Some(car)
//| null -> None
//| Null -> None
let mercedes = getCar("Mercedes")
let car = match mercedes with
| Some c -> c.ToString() // c is null !!!
| _ -> "not found"
FirstOrDefault
不是 return Nullabe,所以我无法匹配 null
。
那么,如何检查匹配表达式中函数的 null
return?
我正在使用 FirstOrDefault,因为我尝试使用 Enumerable 中最简单的对象 (Seq)。
我知道我可以使用从 Enumerable 开始的其他东西,但我仍然想了解我在这里缺少的东西。
[解决方案]
感谢@Abel 建议使用 .tryFind()
我完成了任务
Seq.tryFind()
return 是 Car option
。
let getCar model =
let cars = lazy(
// this.Collection.Indexes.List().ToEnumerable() // this is the real data I'm using (MongoDB indexes of a collection)
// |> Seq.map parseIndex // a function that create Car (Index) from the BsonDocumentBsonDocument
cars.AsEnumerable()
)
cars.Value |> Seq.tryFind(fun c -> c.Model = model)
let mercedes = match getCar("Mercedes") with
| Some c -> c.ToString()
| _ -> "not found"
let ferrari = match getCar("Ferrari") with
| Some c -> c.ToString()
| _ -> "not found"
类 不能将 null
作为适当的值(这是 F# 更强大的方面之一)。但是,您可以通过添加 AllowNullLiteral
属性来打破此约定:
[<AllowNullLiteral>]
type Car(model:string, color:string) =
member this.Model = model
member this.Color = color
现在您可以创建 null
的实例,当您需要与可以 return null
的代码互操作时,在代码中使用它会更容易。 =27=]
请注意,带有 | car ->
的代码是一个变量模式,这意味着它捕获所有内容并将值分配给变量 car
。不确定你想在这里做什么,但是 类 上的模式匹配不是很有用。
如果您需要匹配 null
,将其作为第一个匹配项,第二个匹配项可以是 car
,捕获其他所有内容。您的代码将变为:
[<AllowNullLiteral>]
type Car(model:string, color:string) =
member this.Model = model
member this.Color = color
member this.ToString() = sprintf "ModeL:%s Color:%s" model color
module X =
let cars = [
Car("Ferrari", "red")
Car("BMW", "blu")
]
let getCar model =
match cars.FirstOrDefault(fun c -> c.Model = model) with
| null -> None
| car -> Some(car) // matches everything else
关于您的代码的另一个注意事项:Car
类型也可以作为记录创建:
type Car =
{
Model: string
Color: string
}
而不是使用 LINQ,使用 List.tryFind
(或者 Seq.tryFind
,如果你想使用 IEnumerable
)更惯用,它会自动 return 是一个选项,您不必在 F# 代码中突然引入 null
。您的代码总体上会变得更简单:
type Car =
{
Model: string
Color: string
}
override this.ToString() = sprintf "ModeL:%s Color:%s" this.Model this.Color
module X =
let cars = [
{ Model = "Ferrari"; Color = "red" }
{ Model = "BMW"; Color = "blu" }
]
let getCar model = cars |> List.tryFind (fun x -> x.Model = model)