此博客文章停止维护,访问个人博客链接
下面我们快速的了解下怎么让一个F#的初学者去理解他们不熟悉的语法结构。
很明显1分钟内不可以面面俱到,但是我会尽可能的使你能读懂和理解接下来以及以后面章节所出现的例子。如果你不能完全的理解,不用担心,因为在真正的代码例子中我会给出更加详细的解释。
F#和标准的类C语法有两个重要的不同点:
- F#用缩进代替了C语法中用括号来限定代码块(和Python很相似)
- 用空格来分隔参数而不是逗号
有一些人不是很喜欢F#的语法,如果你也感同身受,那么请考虑下面一句话:
就个人而言,我认为F#语法非常的清晰直白如果你习惯他以后。在很多情况下,它比C#语法更加简单,甚至更少的关键字和特殊处理
下面的F#代码描述了很多常用的基本概念。
我建议你跟着敲打下代码,然后自己尝试着修改下,体会下其中含义:
- 将下面的代码编写进F#文件(以.fsx为扩展名)然后在交互窗口(interactive window)运行它。具体操作借鉴(F#安装与使用)
- 或则,直接在交互窗口上敲代码然后运行(interactive window)。记住在代码结尾用;;告诉编译器你已经编写完毕,准备运行。
// 单行注释用双斜杠 (* 多行注释用 (* . . . *) *) // ======== "变量" (不是真正的变量) ========== // 用let定义不可变值 let myInt = 5 let myFloat = 3.14 let myString = "hello" //不用声明类型 // ======== Lists ============ let twoToFive = [2;3;4;5] // 使用方括号创建list,并用分号间隔 let oneToFive = 1 :: twoToFive // :: 创建一个包换第一个元素(1)的list // 结果 [1;2;3;4;5] let zeroToFive = [0;1] @ twoToFive // @ 符号链接两个list // IMPORTANT: 只要分号作为分隔符,逗号不能被用作分隔符 // ======== Functions ======== // 用 ”let“关键字也可以定义函数名 let square x = x * x // 注意没有括号 square 3 // 执行函数,再次强调没有括号。 let add x y = x + y // 不要用 add (x,y)! 他有完全不同的意思 add 2 3 // 运行函数 // 定义多行函数使用缩进,不需要分号 let evens list = let isEven x = x%2 = 0 // 定义isEven 为子函数 List.filter isEven list // List.filter 是个库函数 // 有两个参数,一个是带bool返回的函数一个是list evens oneToFive // 运行函数 // 你可以用括号去定义优先级. 在下面的例子肿,先执行带两个参数的"map",然后执行"sum" // 没有括号的话, "List.map" 将会作为一个参数传到List.sum中 let sumOfSquaresTo100 = List.sum ( List.map square [1..100] ) //你可以是用"|>"将一个操作的输出作为管道出入到下个操作中 //下面利用管道符实现 sumOfSquares函数 let sumOfSquaresTo100piped = [1..100] |> List.map square |> List.sum // "square" 是之前定义的 // 你可以使用"fun"关键字定义匿名函数或lambda表达式 let sumOfSquaresTo100withFun = [1..100] |> List.map (fun x->x*x) |> List.sum // F#中没有return关键字。一个函数永远在最后一个表达式中返回值 // ======== Pattern Matching ======== // Match..with.. 类似 case/switch 语句 let simplePatternMatch = let x = "a" match x with | "a" -> printfn "x is a" | "b" -> printfn "x is b" | _ -> printfn "x is something else" // 下划线代表任意匹配 // Some(..) and None 模拟空包装 let validValue = Some(99) let invalidValue = None // 这个例子 match..with 匹配"Some"和 "None", // 同时提取"Some"的值 let optionPatternMatch input = match input with | Some i -> printfn "input is an int=%d" i | None -> printfn "input is missing" optionPatternMatch validValue optionPatternMatch invalidValue // ========= Complex Data Types ========= //tuples 快速轻便的构造匿名类型 let twoTuple = 1,2 let threeTuple = "a",2,true //record 类型用于命名字段 type Person = {First:string; Last:string} let person1 = {First="john"; Last="Doe"} //union 类型用于选择 type Temp = | DegreesC of float | DegreesF of float let temp = DegreesF 98.6 //类型可以递归合并成复杂类型 type Employee = | Worker of Person | Manager of Employee list let jdoe = {First="John";Last="Doe"} let worker = Worker jdoe // ========= Printing ========= // printf/printfn 函数类型于C#中的 Console.Write/WriteLine printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true printfn "A string %s, and something generic %A" "hello" [1;2;3;4] // 所有复杂类型都可以很好打印出来 printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" twoTuple person1 temp worker // 可以利用sprintf/sprintfn 函数格式化数据到字符串,类似于String.Format.
理解了上面的基本概念,让我们开始用些例子来比较下F#和C#的不同吧