NetRoc's Blog

N-Tech

 

F#学习笔记之五 — F#程序的组成

NetRoc

http://www.DbgTech.net

F#和很多语言不同,它不一定具有明确的程序入口点,如C语言的main函数。在单源文件程序中,代码是从头至尾执行的。在多源文件程序中,代码需要被组织为模块或者命名空间这样的单位。

模块

默认情况下,F# 将所有代码都放置在匿名模块(anonymous module)中。模块的命名为首字母大写的源文件名。因此,如果在文件file1.fs中有一个名为value1的值,那么可以通过File1.value1来引用它。

创建模块

 

代码中可以在源文件开始处使用module关键字来明确指定模块名。在module定义之后的所有值、函数或类型定义都属于该模块。如:

module Alpha

//在模块外部使用Alpha.x来引用下面的值:

let x = 1

模块嵌套

 

单个源文件中可以包含嵌套的模块。被嵌套的模块应该使用module关键字后跟一个等号来声明。嵌套模块必须比上层模块缩进对齐。如:

module Utilities

module ConversionUtils =

    // Utilities.ConversionUtils.intToString

    let intToString (x : int) = x.ToString()

    module ConvertBase =

        // Utilities.ConversionUtils.ConvertBase.convertToHex

        let convertToHex x = sprintf "%x" x

        // Utilities.ConversionUtils.ConvertBase.convertToOct

        let convertToOct x = sprintf "%o" x

module DataTypes =

        // Utilities.DataTypes.Point

        type Point = Point of float * float * float

命名空间

 

除了模块之外还可以使用命名空间来组织代码。命名空间和模块的唯一区别在于,命名空间中不能包含值,只能包含类型定义。另外,命名空间不能像模块一样嵌套,而只需要直接在同一个源文件中定义多个命名空间。下面的例子在两个命名空间中定义了一些类型:

namespace PlayingCards

// PlayingCard.Suit

type Suit =

    | Spade

    | Club

    | Diamond

    | Heart

// PlayingCards.PlayingCard

type PlayingCard =

    | Ace of Suit

    | King of Suit

    | Queen of Suit

    | Jack of Suit

    | ValueCard of int * Suit

namespace PlayingCards.Poker

// PlayingCards.Poker.PokerPlayer

type PokerPlayer = { Name : string; Money : int; Position : int }

在F#中部推荐同时使用命名空间和模块。模块主要用于快速进行原型定义和快速浏览解决方案。而命名空间主要用于使用面向对象设计的较大型的项目。

程序的启动

 

F#中程序是从最后一个源文件的顶部开始执行的。假如现在有包含下面代码的单文件项目:

// Program.fs

let numbers = [1 .. 10]

let square x = x * x

let squaredNumbers = List.map square numbers

printfn "SquaredNumbers = %A" squaredNumbers

open System

printfn "(press any key to continue)"

Console.ReadKey(true)

在VS 2010中再添加一个新的空F#源文件。这时,最后一个文件是新添加的空文件,因此如果此时按F5运行程序时,不会执行任何代码。

这一点需要特别注意,否则程序的执行可能会对初学者造成混乱。可以说F#这个设计真的是非常之奇怪,不但没有任何好处,还会让人非常之不爽。。。。。。。。。

更正式的做法是使用[<EntryPoint>]属性来定义一个main函数。main函数需要满足以下几个要求:

  • 必须是项目中被编译的最后一个源文件中定义的最后一个函数。
  • 接受单个类型为string array的参数,这是操作系统传递给程序的参数。
  • 返回一个整数,作为程序的退出码。

如果要明确指定main函数,那么上面那个程序应该改写为:

// Program.fs

open System

[<EntryPoint>]

let main (args : string[]) =

    let numbers = [1 .. 10]

    let square x = x * x

    let squaredNumbers = List.map square numbers

    printfn "SquaredNumbers = %A" squaredNumbers

    printfn "(press any key to continue)")

    Console.ReadKey(True) |> ignore

    // Return 0    

    0

posted on 2010-06-20 09:23 NetRoc 阅读(641) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。

导航

统计

常用链接

留言簿(7)

随笔档案(99)

文章分类(35)

文章档案(32)

Friends

Mirror

搜索

最新评论

阅读排行榜

评论排行榜