您的位置:首页 > 其它

F#程序设计-F#语言基础之函数(1)

2009-12-07 21:33 197 查看
函数

到目前为止,我们已经介绍完了F#的基本类型,接下来将要介绍的是怎么定义并且使用函数。

定义函数跟定义值在方式上都是一样的,除了函数名后面带的值被称作参数外,下面定义了一个函数square,作用的将x作为参数,并且返回它的平方:

> let square x = x * x;;
val square : int -> int
> square 4;;
val it : int = 16


不同于C#,F#没有return关键字,因此,当你定义一个函数,最后一个表达式结算的结果将会作为函数的返回值。让我们尝试另一个函数:输入x并且加1:

> let addOne x = x + 1;;
val addOne : int -> int


从FSI交互式窗口中显示出函数的类型是int->int,,也就是说函数的参数接受int类型的值,并且返回值的类型也为int。如果你一个函数有多个参数,那么函数的参数签名也显得复杂多,比如:

> let add x y = x + y
val add : int -> int -> int


" int -> int -> int"从专业术语上来说,表达的意思是"一个函数接受一个整数,返回一个函数,接受一个整数返回一个整数"。不要担心这个“函数返回函数”有点迷惑,你唯一需要知道现在是调用一个函数,只需提供由空格分隔的参数:

> add 1 2;;
Val it : 3


1、类型推断

由于F#是静态类型,调用刚才创建的add方法,并且参数是一个float的话将会导致一个编译器错误:

> add 1.0 2.0;;
add 1.0 2.0;;
----^^^^
stdin(3,5): error FS0001: This expression has type
float
but is here used with type
int.


你可能想知道,为什么编译器认为这个函数只接受整数?其实,+操作符也能够操作float类型的。原因是因为F#的类型推断,不同于C#,F#编译器不要求你明确指明传递给函数的所有参数类型,编译器能够根据参数的使用来推断出类型(请注意不要跟动态类型推理混淆,虽然F#允许你在编写函数时省略参数的类型,这并不意味着类型检查是在编译时执行)。因为+操作符可以在操作不同的类型,比如byte、int以及decimal,所以如果省略参数类型或者在代码块中没有很多的资料来判断类型的话,F#编译器默认为int,就像刚才的add函数样。但是如果在add函数中,通过一个浮点类型来调用它,那么add函数签名将被认为是"float ->float -> float":

> let add x y = x + y
- let result = add 4.0 5.0;;
val add : float -> float -> float
val result : float = 9.0
>


但是,你可以提供一个类型的注释,或暗示来告诉F#编译器是什么类型。要添加类型注释,只需简单的替换下函数的参数按照以下的模板:

ident -> (ident : type)

其中type就是你想要强制转换的参数类型,为了约束add函数的第一个参数为float类型,只需要简单的做一些修改即可:

> let add (x : float) y = x + y;;
val add : float -> float -> float

现在可以看到,因为你在参数中增加了类型注释,那么函数的类型也改为了float -> float -> float。因为通过重载+操作符,让它的第一个参数为float,并且函数的类型也改变成了float -> float -> float,所以F#编译器就能根据这个推断出参数y也是float型。类型推论通过F#编译器确定拥有什么类型,大大降低了代码混乱,但是,偶尔的类型注释是必要的,有时提高代码的可读性。



2、泛型函数

你可以编写一个拥有任何参数类型的函数,例如,一个返回它的参数的函数:

> let ident x = x;;
val ident : 'a -> 'a
> ident "a string";;
val it : string = "a string"
> ident 1234L;;
val it : int64 = 1234L

因为类型推断不能确定值x为一个固定类型在indent函数中,它是泛型的,如果一个参数是泛型,这意味着该参数可以是任何类型,如整数,字符串或浮点数。一个泛型参数类型的名称可以为任何有效的标识符加上一个撇号作为前缀,但通常都是以小写字母'a'开始,下面的代码重新定义了ident函数,并且为x增加了一个类型注释,标识为泛型:

> let ident2 (x : 'a) = x;;
val ident2 : 'a -> 'a

编写通用的代码对于最大限度地提高代码重用是非常重要的,在以后的介绍中,将会对泛型函数继续深入介绍,现在仅仅所要知道的是当看到'a这样的类型时,它可以是一个int,浮点,字符串,用户定义的类型等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: