重口味警告:本篇适合于追求代码直观到偏执狂地步,和宁愿绞尽脑汁减少几次击键的程序员,不喜勿入!
在Ruby里我们可以写出这样的代码:
hash.if_has_key k do |val|
#do sth. with val
end
这段代码描述性太强了,以至不需要解释就能让人明白。而且对比普通写法:
if hash.has_key k then
val = hash[k]
...
end
< p>省了不少打字的功夫。为了在F#里也有这样的效果,我想了两种方法。首先,可以模拟Ruby。实现if_has_key的关键一是开放 class--事前要将if_has_key方法加入hash的类,二是block。F#和C# 3.0一样支持extension methods,而lambda expression可以代替block(虽然不完美),因此可以这样:#light
type System.Collections.Generic.IDictionary with
member this.if_has_key k f =
if this.ContainsKey k then
f this.[k]
else
()
于是:
let tbl = dict [(1, "one"); (2, "two");]
tbl.if_has_key 1 (fun val->
print_any val |>ignore)
可是fun关键字实在扎眼,也只能感叹Ruby的设计至少在格式层面是很巧妙的了。第二种方法利用F#的active pattern功能:
let
(|HasKeyVal|_|)<'kt, 'vt> k
(d:System.Collections.Generic.IDictionary<'kt,
'vt>) =
if d.ContainsKey k then Some(d.[k])
else None
于是:
match tbl with
| HasKeyVal 2 v -> print_any v
| _ -> ()
缺点一是match关键字在这个地方不伦不类,二是要跟个尾巴|_->() 。好处是可以像swich包含多个case一样:
match tbl with
| HasKeyVal k1 v -> ...
| HasKeyVal k2 v -> ...
| HasKeyVal k3 v -> ...
| _-> ()
程序会依次测试tbl是否包含k1,k2,k3。这样的程序对比起用if...then...elseif...else写出来的版本节省就比较可观了。