2014年11月11日 星期二

C# Function函數,程式的編程執行者

如果一個程式師,對於函數這個名稱還不夠了解的話,那真的是要砍掉重練。基本上,早期的程式,是沒有所謂的函數這個名稱的,但它的誕生,開啟了程式一個很重要的里程。

函數式編程於1958年被創造出來的LISP了,透過LISP,可以用精簡的人力。較現代的例子包括scheme、Haskell、Clean、Erlang和Miranda等。雖然λ演算並非設計來於計算機上執行,但可視為第一個函數式編程語言。1980年代末期,Haskell發佈,企圖集合很多函數式編程研究裏的想法。

Functional programming函數式編程或者函式程式設計,又稱泛函編程,是一種編程典範,它將電腦運算視為數學上的函式計算,並且避免使用程式狀態以及易變物件。函數程式語言最重要的基礎是λ演算(lambda calculus)。而且λ演算的函式可以接受函式當作輸入(引數)和輸出(傳出值)。簡單的說,以前的程式同樣的一個寫法,常因為不同的功能,就要重新再寫出一個相似的陳述句。這對於開發者而言,不僅很花時間在除錯Debug上,而且重覆使用性差。它的誕生就是為了解決這樣的問題。

C#分為靜態函數與成員函數兩類,靜態函數附屬於類別,呼叫時可以直接指定類別名稱即可。成員函數附屬於物件,呼叫時必須透過物件變數進行呼叫。

函數會接收到呼叫端傳入的參數。C# 的參數有數種傳遞方式,包含傳值參數 (call by value),傳址參數 (call by reference) 等,基本型態的參數,像是 int, double, char, … 等,也可以是void,而物件形態的參數,像是 StringBuilder,陣列等,預設則是使用傳址的方式。

下面例子是 C# 的靜態函數範例,其中的 square 就是靜態函數,其功能是將傳入的數值進行平方動作後傳回,這是一個傳值參數的範例。

class Draw
{
    public static void Main(string[] args)
    {
        int x = square(5);
        Console.WriteLine("x="+x);
    }

    public static int square(int n)
    {
        return n*n;
    }
}

陣列也可以用來作為函數的參數,陣列的傳遞採用傳址的方式,因此在函數中對陣列的修改將會是永久性的修改,離開函數後並不會恢復成原先的數值。

class Example
{
    public static void Main(string[] args)
    {
        int[,] a = {{1,2}, {3,4}};
        int[,] b = {{5,6}, {7,8}};
        int[,] c = new int[2,2];
        add(a, b, c);
        Console.WriteLine("=======a=======");
        print(a);
        Console.WriteLine("=======b=======");
        print(b);
        Console.WriteLine("=======c=======");
        print(c);
    }

    public static void add(int[,] x, int[,] y, int[,] z)
    {
        for (int i=0; i<z.GetLength(0); i++)
        for (int j=0; j<z.GetLength(1); j++)
        {
         z[i,j] = x[i,j] + y[i,j];
        }
    }

    public static void print(int[,] x)
    {
        for (int i=0; i<x.GetLength(0); i++)
        {
            for (int j=0; j<x.GetLength(1); j++)
                Console.Write(x[i,j]+" ");
            Console.WriteLine();
        }
    }
}

上面範例中的 add 函數用來將兩個二維陣列 (x,y) 相加,然後將結果放入 z 當中,print 函數則是將傳入的陣列 x 印出來。必須注意的是,對於二維陣列而言,要取得陣列的第一維元素個數 (列數),可用 GetLength(0),要取得陣列的第二維元素個數 (行數),必須使用 GetLength(1)。

函數基本上在許多的程式語言都會有,不過有一點要注意的是,在ActionScript 3上的函數,是可以當作變數使用。如果一開始接觸ActionScript 3的人再來寫C#的話,會誤以為C#的函數也可以像ActionScript 3一樣的使用。ActionScript 3如下例子:

var func:Function = new Function()
                               {
                                   trace("可以使用成變數的Function");
                               };
func();//這邊就執行了上面的函數

上面的例子,就是ActionScript 3很典型的使用方法,但是C#對於安全性的要求很嚴謹,所以不允許Funtion可以這樣的使用,所以千萬要注意。