本文鏈接:http://www.cnblogs.com/hjklin/p/fs-for-cs-dev-1.html
簡單介紹
F#(與C#一樣,念作“F Sharp”)是一種基於.Net框架的強類型、靜態類型的函數式編程語言。
可以說C#是一門包含函數式編程的面向對象編程語言,而F#是一門包含面向對象的函數式編程語言。
可以查看官方文檔了解更多信息。
本系列文章假設你在了解C#的情況下,將F#與C#在異同點上進行說明,讓讀者能快速地對F#有個系統的了解。
才疏學淺,錯漏難免,如果您在閱讀過程中有什么建議或意見,還請不吝指教。
函數式編程這幾年一直不溫不火,但相信了解了F#之后,對C#也會有更深的認識,對學習其他函數式語言也會更容易上手。
Hello, World
在使用F#時,可以像C#一樣創建一個控制台項目進行測試。
但因為F#支持以腳本形式運行,所以直接打開F# Interactive(以下簡稱fsi)進行交互是最方便的。
在Visual Studio中可在“視圖-其他窗口”中打開。以前沒有csi的時候,一直拿fsi來測試C#代碼,在VS2015中終於添加了csi。
如果不想打開臃腫的VS,可在Microsoft SDK的安裝位置找到fsi。以下是我安裝的F# 4.0的fsi的位置:
"C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0\Fsi.exe"
介紹任何語言的特有方式就是通過那幾乎成為標准的“Hello, World”程序。
F# 輸出可使用 printf
函數,如下:
printf "Hello, world!"
當然,也可以像C#一樣使用 .Net 的控制台輸出函數:
System.Console.Write("Hello World")
當把以上代碼敲進fsi里按回車后,會發現並沒反應,是因為在fsi里提交代碼必須以;;
雙分號結尾。
請輸入 printf "Hello, world!";;
和 System.Console.Write("Hello World");;
或者在換行后輸入;;
再次回車。
如圖:
F#基礎類型
下面,我們嘗試把以下簡單的C#代碼轉換成F#代碼:
int sum = 0;
for (int i = 0; i<=100; i++)
{
if (i%2 != 0)
sum += i;
}
Console.WriteLine("0到100中的奇數的和為{0}", sum);
這段命令式代碼只是簡單地把0到100中的奇數相加,並把和輸出。
雖然在C#中也支持函數式,但在這里我們為了了解基本語法,使用簡單語句來介紹。
以下是F#版本的代碼:
let mutable sum = 0
for i = 0 to 100 do
if i%2 <> 0 then sum <- sum + i
printfn "0到100中的奇數的和為%A" sum ;;
以上代碼在fsi里的運行結果為:
0到100中的奇數的和為2500
val mutable sum : int = 2500
val it : unit = ()
可以看出,F#中每行代碼結尾的;
是可選的。
因為函數式編程語言的特點之一便是無副作用(No Side Effect)、不可變(Immutable),所以沒有變量(Variable)的概念,只有值(Value)的概念。
所以在上面的運行結果中,都是以val開頭;而值it
默認為最后一次運行結果,在此例中其類型為unit
,相當於C#中的void
,即無返回值。
但是在很多場景下,Mutable(可變)可以帶來很多便利,尤其是在像上面結合命令式編程的場景中。
在上面的代碼中,val mutable sum
即為一個可變的值。
基礎類型
下面將C#和F#的數據類型定義作對比:
數據類型 | C# | F# |
---|---|---|
Int | int i = 0; | let i = 0 let i = 0l |
Uint | uint i = 1U; | let i = 1u let i = 1ul |
Decimal | decimal d = 1m; | let d = 1m let d = 1M |
Short | short c = 2; | let c = 2s |
Long | long l = 5L; | let l = 5L |
unsigned short | ushort c = 6; | let c = 6us |
unsigned long | ulong d = 7UL; | let d = 7UL |
byte | byte by = 86; | let by = 86y let by = 0b00000101y let by = ‘a’B |
unsigned byte | sbyte sby = 86; | let sby = 86uy let sby = 0b00000101uy |
bool | bool b = true; | let b = true |
double | double d = 0.2; double d = 0.2d double d = 2e-1 double d = 2 double d0 = 0 |
let d = 0.2 let d = 2e-1 let d = 2. let d0 = 0x0000000000000000LF |
float | float f = 0.3; foat f = 0.3f; float f = 2; float f0 = 0.0f; |
let f = 0.3f let f = 0.3F let f = 2.f let f0 = 0x0000000000000000lf |
native int | IntPtr n = new IntPtr(4); | let n = 4n |
unsigned native int | UIntPtr n = new UIntPtr(4); | let n = 4un |
char | char c = ‘c’; | let c = ‘a’ |
string | string str = “abc\n”; string str = @"c:\filename"; |
let str = “abc\n” let str = @"c:\filename" |
big int | BigInteger i = new BigInteger(9); | let i = 9I |
F#的字面量詳細介紹可查看MSDN文章。
十六進制、八進制和二進制
我們知道,在C#中,可以用0x
前綴定義十六進制數值。
而F#中除了十六進制(0x
),還可以直接定義八進制(0o
)和二進制(0b
)的數值。
let hex = 0xFABC
let oct = 0o7771L
let bin = 0b00101010y;;
輸出結果為:
val hex : int = 64188
val oct : int64 = 4089L
val bin : sbyte = 42y
浮點數
需要注意的是,在F#里,double
和float
都代表雙精度浮點數,單精度浮點數稱為float32
。
String
還有一個字面量表示方法是三個雙引號:
let str = """<book title="Paradise Lost">
<content />
</book>"""
在使用@
為前綴(稱為Verbatim String)時,字符串內的若出現雙引號必須使用兩個雙引號轉義,使用三個雙引號的表示法避免了這個問題。
這種表示法最常用在把XML文檔編碼到代碼文件里。
字節數組
在類型對比表中,byte行可以看到有一個創建字節數組的語法:
let asciiBytes = "abc"B // val asciiBytes : byte [] = [|97uy; 98uy; 99uy|]
其等價的C#代碼是:
byte[] asciiBytes = Encoding.ASCII.GetBytes("abc");
當然,只支持ASCII編碼。
變量名
F#的變量名命名規則與C#基本一致,但也可在變量名中包含單引號'
:
let x = 10
let x' = 11
let Tom's = "2010"
通過let
關鍵字,將10
綁定(賦值)到x
,將11
綁定到x'
。
在C#中,若要將關鍵字或保留字作為變量名,則可以變量名前加@
實現:
例如使用代碼
class @class {}
定義一個名為class的類。
但是在F#中,只需在前后加上``
即可將任意字符串指定為變量名:
let ``let`` = 4
let ``I love F#`` = "This is an F# program."
(*
在fsi的輸出結果為:
val let : int = 4
val ( I love F# ) : string = "This is an F# program."
*)
注意在F#中,單行注釋和C#一樣使用//
,但多行注釋使用(* *)
。
F#的運算符與C#類似,部分區別將在下一篇介紹。感興趣的可以在fsi里嘗試輸入運算玩一玩,或許就可以發現區別了。