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

3、函数的生命周期
   在函数内定义的每个值都有一个特定的范围,也即是它使用的生命周期。默认情况下,定义后的值作用范围在于它所在的模块内,意味着值一旦申明后就可以在任意地方使用。然后,如果指定义在函数内,则它的作用范围仅限于它的函数内。因此,一个函数可以任何函数外面定义的值,但函数外面的其它地方则不能引用一个函数内部定义的值。下面,我们将定义一个在模块范围内的值moduleValue并使用在一个函数functionA中以及定义一个作用于函数内部的值functionValue,同时在函数外部调用functionValue将引发一个未定义异常:
> // Scope
let moduleValue = 10
let functionA x =
x + moduleValue;;
val moduleValue : int = 10
val functionA : int -> int
> // Error case
let functionB x =
let functionValue = 20
x + functionValue
// 'functionValue' not in scope
functionValue;;
functionValue;;
^^^^^^^^^^^^^
error FS0039: The value or constructor 'functionValue' is not defined.

 

值的作用范围看起来并不是很重要的一个细节,重要的是在F#,因为它允许嵌套函数,在F#中,你可以在一个函数的块内申请一个新的函数。嵌套函数可以获取更高一层作用范围内的任何值,比如它的父函数、所在的模块以及在嵌套函数内新定义的值。下面的代码显示嵌套在实际中的应用, 请注意函数g能够利用其父函数f's参数fParam:
> let moduleValue = 1
- let f fParam =
-     let g gParam = fParam + gParam + moduleValue
-     let a = g 1
-     let b = g 2
-     a+b;;

val moduleValue : int = 1
val f : int -> int

 

在一个函数中定义一个函数,它看起了只能导致混乱,但是在限制函数的作用范围上有非常有用的,同时从职能上讲,也说明特定的功能仅仅利用在需要的地方,它有助于防止模块污染。如果在一个嵌套函数内想申请一个x值,但是在更高一层范围中已经存在了x值,会是什么样呢?在F#中,两个相同名字的值并不会引起编译错误,相反,它将会导致覆盖前面的x值。当发生这种情况,这两个值都存在于内存中,除非是没有办法访问先前声明价值,否则最后一定申明的将会被使用,比如下面的函数:
> let bytesToGB x =
-     let x = x / 1024I   // B to KB
-     let x = x / 1024I   // KB to MB
-     let x = x / 1024I   // MB to GB
-     x;;

val bytesToGB : System.Numerics.BigInteger -> System.Numerics.BigInteger

> let hardDriveSize = bytesToGB 268435456000I;;

val hardDriveSize : System.Numerics.BigInteger = 250

 

在上面的例子中,在每次let绑定到一个x值后,前面的值将会被后面的所代替,表明上看起来x值的已经变化了,但实际上它创建了一个新的x值,只是名字相同而已。下面的例子显示了如何得到编译后代码:
> let bytesToGB x =
-     let x_2 = x / 1024I // B to KB
-     let x_3 = x_2 / 1024I // KB to MB
-     let x_4 = x_3 / 1024I // MB to GB
-     x_4;;

val bytesToGB : System.Numerics.BigInteger -> System.Numerics.BigInteger

 

4、控制结构
在一个函数,你可以使用if关键字来控制流程分支,if语句的条件表达式必须是bool类型,并且如果为true,则执行语句。下面的代码将在控制台中打印一个消息:
> let printGreeting shouldGreet greeting =
-     if shouldGreet then
-         printfn "%s" greeting;;

val printGreeting : bool -> string -> unit

> printGreeting true "Hello!";;
Hello!
val it : unit = ()
> printGreeting false "Hello again!";;
val it : unit = ()

 

可以使用if关键字控制更复杂的分支流程,if表达式跟C#的是一样的: 如果条件表达式的值为真,那么第一个代码块执行,否则,代码的第二块执行,然而,有些事情使得F#与其他语言不同的是,if表达式返回一个值,在下面的代码中,在if表达式中值result绑定到一个结果,所以如果x % 2 = 0, result的值是"Yes it is"; 否则就是"No itis not":

> let isEven x =
-     let result =
-         if x % 2 = 0 then
-             "Yes it is"
-         else
-             "No it is not"
-     result;;

val isEven : int -> string

> isEven 5;;
val it : string = "No it is not"
> isEven 4;;
val it : string = "Yes it is"

 

if表达式可以使用嵌套来实现更复杂的流程分支, 但很快变得难以维持,比如:

> let isWeekend day =
-     if day = "Sunday" then
-         true
-     else
-         if day = "Saturday" then
-             true
-         else
-             false;;

val isWeekend : string -> bool

 

F#提供了elif关键来代替if表达式嵌套的语法,利用它,可以将多个if表达式链接在一起而没有不要使用嵌套,比如下面的代码:

> let isWeekday day =
-     if day = "Monday" then true
-     elif day = "Tuesday" then true
-     elif day = "Wednesday" then true
-     elif day = "Thursday" then true
-     elif day = "Friday" then true
-     else false
- ;;

val isWeekday : string -> bool

因为if语句最后都要返回一个值,所以在所有的if分支中,返回值的类型都必须是相同的,否则会出错:

> let x =
-     if 1 > 2 then
-         42
-     else
-         "a string";;

          "a string";;
  --------^^^^^^^^^^

stdin(52,9): error FS0001: This expression was expected to have type
    int
but here has type
    string

 

但是如果你仅仅只有一个if并且没有elif,该怎么做呢?这种情况下必须使用unit,unit在F#中是一种特殊的类型,意思就是没有返回值(跟C#中的void是一样的),下面的代码演示了返回unit的类型:

> let describeNumber x =
-     if x % 2 = 0 then
-         printfn "x is a multiple of 2"
-     if x % 3 = 0 then
-         printfn "x is a multiple of 3"
-     if x % 5 = 0 then
-         printfn "x is a multiple of 5"
-     ();;

val describeNumber : int -> unit

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值