那為什麼在2023年的現在,那麼多新的語言和技術,我們還要來了解f#呢?
f#和c#一樣,也是基於.net平台的語言,了解了語法後,就能快速地使用.net框架甚至c#編寫的框架,
而且在學習過程中.net框架中很多以前不理解的東西,通過f#就變得很容易理解了。作為.net程式設計師,還是值得了解的。 函式式語言的「天然支援非同步和並行」的能力,也使得多執行緒開發變得簡單。
c#在最近的版本中經常得益於f#對.net框架的推進,如加入了async關鍵字,有 tuple了(雖然在語法層面不支援)等等。 在最近發布的.net core中,也可以通過dotnet new -l f#來建立f#專案。.net core裡f#的坑,這裡就不細說了。 ?? 通過.net部落格,也可以發現越來越多人在使用f#。
f#並無法替代c#,但兩者卻能起到互補的作用。
記得《七周七語言》裡說過:
每學一門新的語言,思維方式都會發生改變。程式語言亦是如此。
作者在書中說,每學習一門語言都會去找互動教程,但大多數情況下並找不到稱心如意的。
若想領會一門語言的精髓,它(指互動教程)可就無能為力了。我想要的是那種痛快淋漓、深入探索語言本質的感覺。
我是沒有作者的這種能通過探索語言本質的能力來介紹f#,但希望也能讓大家發現f#語言的動人心弦之處。
廢話說得有點多了,下面繼續介紹f#吧。
我們再翻出上一篇的小例子:
let mutable sum = 0
for i = 0 to 100 do
if i%2 <> 0 then sum
四則運算和模運算(取餘)不必多說,但對於浮點數(float和float32)型別,還支援**(冪)語法。
2. ** 3.;; // val it : float = 8.0像abs、sin等這些基本數學函式在f#裡也包含在操作符(operators)的模組裡,所有操作符可在msdn文章(core.operators module(f#))檢視。
在上一篇的數值型別對比中,我們可以看出,f#在語法層面上支援大整數。
大整數於.net 4.0新增到框架中,在system.numerics模組裡。f#建立專案時預設引用了此dll。(大整數也支援**運算子,但指數必須為int,其實就是pow方法。)
let bigint = 4325i;; //相當於c#的 var bigint = new biginteger(4325);
3i ** 8;; // val it : system.numerics.biginteger = 6561 ...在記憶體足夠的情況下,biginteger支援任意大的整數。 通過大整數,我們也可以自己實現大實數,或直接使用第三方類庫。
在f#中,沒有隱式型別轉換,就連int到long或float也沒有。所以,數值型別轉換使用返回對應型別的轉換函式:
int 2.5;; // 2
float "3.1415" // 3.1415
(float 2)**(float 3);; 當然也可以使用.net框架的system.convert靜態類。上述方法在轉換字串時也是呼叫的此方法。
f#中的位運算子均使用三重符號:
運算子 名稱 示例 結果 &&& 與 0b1111 &&& 0b0011 3 \ \ \ ~~~ 取反 ~~~0b0011 -4 ^^^ 異或 0b0011 ^^^ 0b0101 6 <<< 左移 0b0001 <<< 3 8 >>> 右移 0b1000 >>> 3 1
注:「或」使用|||,部落格園的markdown渲染時,竟然不支援**裡的|轉義。??
因為函式式語言中,數值不可變,所以=在f#中並不是賦值符號。
=在f#執行相等比較操作,而不等則為<>,這兩個符號與c#有異:
5=8 ;; //false
"ax"<>"ay" ;; //true那就會有人說,f#也有可變的值啊,怎麼賦值呢!沒錯,在上面的示例**中sum為可變值,每次迴圈通過好詭異但又好有道理的符號啊! ??
所以需要注意,c#中的 int i = 1; 其實是相當於f#中的 let mutable i = 1 。因為c#預設建立的是可變型別。請檢視後面的while迴圈介紹。
此外,f#中還有乙個compare函式用來比較兩個值:
compare 31 31;; // 0
compare 5 4;; // 1
(* compare x y
若x > y則返回1;若x < y則返回-1;若x = y則返回0
*)這個比較在c#中有實現過icomparable介面的應該了解,其實compare函式的引數就是需要實現了icomparable介面的型別。
在.net中,比較是乙個複雜的話題,在此就不展開了,可參考msdn文章(object.equals方法和icomparable 介面)。
下面是0到100的迴圈,從0列印到100:
c# **:
for (int i=0; i<=100; i++) f# **:
for i=0 to 100 do printfn "%i" i
for i in [0..100] do printfn "%i" i
for i=100 downto 0 do printfn "%i" i //逆向迴圈,從100到0f#版本中的[0..100]是建立乙個從0到100的列表(list),在之後列表模組會進行介紹。
遺憾的是for ... to和for ... downto語句無法建立如for (int i=0; i<=100; i+=2)這種間隔不為1的迴圈,只能使用for ... in再加上乙個列表。
while迴圈語句
用while迴圈實現的從0列印到100:
c# **:
int i = 0;
while (i <= 100)
f# **:
let mutable i = 0
while i <= 100 do
printfn "%i"
i 需要注意的是,f#中並沒有do...while的迴圈,在for迴圈和while迴圈中,也都沒有break和continue關鍵字。
剛開始接觸f#或習慣了c#的迴圈語句可能會不習慣,但當你熟悉了函式式程式設計的思想後,會發現這些在f#中都是不重要的,甚至迴圈語句都是不必要的。
同時,也盡量不要使用可變型別。因為值的不可變性,使多執行緒程式設計變得簡單;而在c#中,因為值預設為可變的,使程式在多執行緒執行中增加了很多不確定因素。
在上面的示例**中已經使用過if語句。
在f#中,if語句的完整結構是這樣的:
if x>y then "x大於y"
elif xy then printfn "x大於y" //if分支無返回值在f#的if語句中,每個分支必須返回相同型別的值,但不需要return關鍵字(在介紹函式時會涉及)。
如果if分支沒有返回值(即返回unit),則else為可選的;否則,必須有else分支。(類似於c#的?:操作符,但f#中沒有這個操作符。)
c#中的else if在f#中為elif。
在c#中,還有一種分支結構的語句是使用switch...case。在f#中類似的語法是match...with。
c# **:
int i = 1;
switch (i)
f# **:
let i = 1
match i with
| 1 -> printfn "this is one"
| 2 -> printfn "this is two"
| 3 -> printfn "this is three"
| _ -> printfn "this is anything else"其中_為萬用字元,與c#switch中的default類似。
但f#中的match語句功能非常強大,可檢視msdn文章match表示式(match expressions)和
模式匹配(pattern matching)。
模式匹配在函式式程式設計中有著作用,在之後的函式式程式設計中也會進行介紹。
在下一篇中,我們來了解陣列和列表,以及一些f#特有的型別。
關於WebRTC,各種開源Codec和F22戰鬥機
webrtc很強大,出自gips的的名家之手的產品果然不同。以前qq,skype,cisco webex 等很多語音大型應用公司都是用這個引擎,在gips被google收購並開源之後,這些大廠反而因為失去維護而變得不知所措。紛紛自己組織人馬開發各自的引擎。這裡有兩個問題,乙個是付錢買產品與維護的問題...
關於WebRTC,各種開源Codec和F22戰鬥機
webrtc很強大,出自gips的的名家之手的產品果然不同。以前qq,skype,cisco webex 等很多語音大型應用公司都是用這個引擎,在gips被google收購並開源之後,這些大廠反而因為失去維護而變得不知所措。紛紛自己組織人馬開發各自的引擎。這裡有兩個問題,乙個是付錢買產品與維護的問題...
電腦開機,需按F2才能開機怎麼辦
大多數使用計算機的人都會遇到開機故障這一問題,電腦開機故障是很常見的問題之一。開機故障的問題各種各樣,不知道你是否遇到過電腦每次開機都要按f2才能繼續執行這一問題,這是是怎麼回事呢?依據我在u深度所看到一篇文章,總結分享給大家關於電腦開機的時候,需要 按f2才能繼續執行的處 理方法。按f2才能進入系...