3.2.3 计算元组
目前为止,我们还只是用这个示例创建和输出元组,现在,我们要对元组进行一些计算。假设去年增加大量的新生人口,我们就要增加居民人数。
我们知道,元组类型是不可变的,因此,不可能设置 C# 元组类的属性。在 F# 中,有两个读元组值的函数(fst 和 snd),也没有设置值的函数,情况是类似的。因此,计算必须遵循通常的函数模式,通过复制初始元组返回新的元组,城市名不变,人口加上新增数量。
清单 3.9 是 C# 的实现,我们没有在清单 3.7 的Tuple<T1, T2> 类中添加方法,而是作为扩展方法。这是使用 .NET4.0 库中成品(密封,sealed)元组类型方法的常见做法。
清单 3.9 增加城市人口 (C#)
static class TupleExtensions {
public static Tuple<T1, T2>WithItem2<T1, T2>
(this Tuple<T1, T2> tuple, T2newItem2) { [1]
return Tuple.Create(tuple.Item1, newItem2);
}
}
var pragueOld =Tuple.Create("Prague", 1188000);
var pragueNew =pragueOld.WithItem2(pragueOld.Item2 + 13195); [2]
PrintCity(pragueNew);
WithItem2 方法[1]把元组中第二个元素的新值作为参数,使用 Tuple.Create 方法创建新的元组,第一个元素从当前元组(this.item1)复制,第二个元素为新值 newItem2。清单还显示了如何使用这个方法,创建有关 Prague 的城市信息,人口增加了 13195 后[2],得到下一年的新值。
现在,我们想用 F# 实现同样的功能,写一个函数 withItem2(清单 3.10),与前面 C# 示例中的 WithItem2 方法功能完全相同。
清单 3.10 增加城市人口 (F#)
let withItem2 newItem2 tuple =
let(originalItem1, originalItem2) = tuple [1]
(originalItem1,newItem2) [2]
let pragueOld = ("Prague",1188000)
let pragueNew = withItem2 (snd(pragueOld) +13195) pragueOld
printCity(pragueNew)
清单 3.10 首先实现了函数 withItem2。我们可以只简单在使用 fst 函数,读取元组第一个元素的值,但为了演示 F# 元组的另一个功能,我们使用模式匹配(pattern matching)。可以看到,在函数的内部,我们首先把给定的元组参数分解为两个单独的值[1],这就发生了模式匹配,在等号左边的语言结构,叫“模式(pattern)”,右边是一个表达式,根据模式进行匹配。模式匹配取表达式的值,将它分解成在模式中使用的值。
在下一行[2],我们就可使用通过模式匹配,从元组中提取的originalItem1 了。我们使用这个值作为第一个元素,给定的参数(newItem2)作为第二个元素,重建元组。(在下一节,将有更多有关元组模式匹配的示例)。除了模式匹配以外,代码没有任何新的内容,但模式匹配是一个重要的主题,F# 还提供了其他模式匹配使用元组的方法,需要仔细看看。