最近我在阅读Apress出版社的《Expert F#》书籍,主要是在构建一个玩具般的F#库时使用它作为参考资料,但有一件事情我无法理解,那就是“Option”类型。
它是如何工作的,以及它在现实世界中的用途是什么?
let stringLength (str:Option<string>) =
match str with
| Some(v) -> v.Length
| None -> -1
类似于:
int StringLength(string str)
{
if (str != null)
{
return str.Length;
}
else
{
return -1;
}
}
我认为一般的想法是,强制你(几乎)处理“没有关联值/对象”的情况可以使你的代码更加健壮。
现实世界中使用最佳的例子之一是在 .Net 中用于 TryParse 模式。请参见
http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!181.entry 的前半部分进行讨论。
当函数或方法“可能”或“可选”返回值时使用它。在C#中,您可能会返回null,或者返回Null Object或可能是值类型的Nullable。
返回null(最常见的情况)的缺点是它不是类型安全的:null是所有类型的实例,因此您会在以后遇到各种棘手的空引用情况。
Option类型是一种所谓的带有两个构造函数的区分联合类型:None和Some a。 None明确表示您没有值。基本上,这是通用的Null Object模式。
除了其他回答之外,Option类型并没有什么特别之处——它只是另一个带标签的联合类型。你可以在一行代码中自己定义它:
type 'a Option = None | Some of 'a
当一个值是可选的时候,你可以使用它。其中一种用途是创建一种类似于“空引用”的效果,例如:
val x : int option ref = None
然后您可以稍后将x更新为某个v。您可以在match语句中使用它,例如:
match !x with (* dereference x *)
None -> (* No value, do something *)
| Some v -> (* Value v, do something else *)
使用选项类型的功能模式:
当您需要更改递归数据结构(例如树或列表)的某些部分时,您将希望尽可能重用现有数据结构。选项类型可以帮助您实现这一点。 这两个函数都将数字5的所有出现替换为7,但第一个函数复制了整个树。第二个函数则没有。
type Tree = Leaf of int
| Node of Tree * Tree
let rec replace_no_sharing tree =
match tree with
| Leaf 5 -> Leaf 7
| Leaf x -> Leaf x
| Node (a, b) -> Node (replace_no_sharing a, replace_no_sharing b)
let replace_with_sharing tree =
let rec replace_option tree =
match tree with
| Leaf 5 -> Leaf 7 |> Some
| Leaf x -> None
| Node (a, b) -> match replace_option a, replace_option b with
| None, None -> None
| Some a, Some b -> Node (a, b) |> Some
| Some a, None -> Node (a, b) |> Some
| None, Some b -> Node (a, b) |> Some
match replace_option tree with
| None -> tree
| Some tree -> tree
在所有情况下可能并不是必要的,但这是一个不错的技巧需要了解。
None
),并返回Some length
或None
。这将使您的编码更加安全,无NRE,并且希望更少出现错误。为了帮助您做到这一点,以便您不必一遍又一遍地重复匹配,FP定义了Option.map/bind
函数。不过,您最后的陈述非常正确 :) - Abel