函式,參數,傳回值介紹
訂閱 375
函式
函式是程式設計中的重要概念,他提供可重複使用的功能,其內部邏輯對外隱藏,呼叫方需要向函式傳遞必要的資訊,函式則將運算結果傳回給呼叫方。
為何使用函式?
避免麻煩是一種單純的動機,誰都無法忍受維護大量重複的程式碼,將功能和邏輯相近的程式碼放入一個函式中,並通過傳遞不同的資訊,對其實作的功能進行細微的調整,這會是一件很好的事。
函式種類
不同語言對函式種類的劃分可能不同,但從提供功能這一角度來看,很多概念可以歸入函式概念中。比如,類別的方法,類別的屬性,類別的運算子,雖然他們在語法上與函式有所區別,但本質上卻是一致的。
參數
為了更加的靈活,運用範圍更廣,函式擁有自己的參數,可以接受呼叫方指派。通過這樣的方式,函式所實作的功能將是可調整的。
選擇性參數
選擇性參數,顧名思義,是在呼叫函式時可以選擇性設定的參數,如果你忽略他們,那麽他們將被賦予預設值。
為何使用選擇性參數?
試想某個參數總被賦予同樣一個值的情況,將其改為選擇性參數會是一個很好的方案。
在下面的 C# 程式碼中,函式Welcome
擁有一個選擇性參數message
,他的預設值是"你好!{0}"
。
// 顯示歡迎訊息的函式
void Welcome(string name, string message = "你好!{0}")
{
Console.WriteLine(message, name);
}
// 可以不為選擇性參數 message 指定值
Welcome("大花貓");
你好!大花貓
可變參數
在大多數語言中,可變參數是通過陣列來實作的,他使得函式可輸入引數的個數不確定,開發人員可以根據自己的需要,傳遞一個,兩個或更多。當你為函式定義可變參數後,一般不能繼續定義其他參數,因為在為這些參數轉遞值時,可能無法確定傳遞目標。
什麽是引數?
引數可以被理解為,在函式被呼叫時,實際傳遞給參數的值。
在下面的 C# 程式碼中,函式ListFruit
擁有可變參數list
,他可以接受多個引數。
// 顯示一組水果的函式
void ListFruit(params string[] list)
{
Console.WriteLine($"一共有 {list.Length} 個水果");
foreach (string fruit in list)
Console.WriteLine(fruit);
}
// 傳遞多個引數
ListFruit(
"一個橘子",
"一個蘋果",
"還是一個蘋果"
);
一共有 3 個水果
一個橘子
一個蘋果
還是一個蘋果
具名參數,位置參數
具名參數是指按照名稱來為指定的參數指派,這種方式可以讓你在一定程度上忽略參數的順序。與具名參數相對應的是位置參數,他按照參數定義時的位置來為參數指派,這種方式是最為常見的。
在實際的開發過程中,具名參數和位置參數經常被混合使用,不過一些語言規定使用位置參數必須在使用具名參數之前。
在下面的 C# 程式碼中,函式CreatePlan
擁有三個參數,name
,days
,leader
。
// 一個用於建立計劃的函式
void CreatePlan(string name, int days, string leader)
{
// 顯示計劃的相關資訊
Console.WriteLine($"計劃 {name}:");
Console.WriteLine($"\t天數 {days}");
Console.WriteLine($"\t領導 {leader}");
}
// 呼叫函式 CreatePlan,days 參數最後指派
CreatePlan(
name: "搬家計劃",
leader: "鏟屎官",
days: 5
);
// 混合使用兩種方式為參數指派
CreatePlan(
"另一個計劃",
days: 100,
"另一個鏟屎官"
);
計劃 搬家計劃:
天數 5
領導 鏟屎官
計劃 另一個計劃:
天數 100
領導 另一個鏟屎官
傳回值
在結束時,函式可以將某個值傳回給呼叫方,以說明本次的執行情況或結果,這個值也就是函式的傳回值。當你不指定傳回值時,大部分語言會為函式傳回一個預設的值。
下面的 C# 函式Sum
傳回了加法運算的結果。
// 一個用於計算加法的函式
int Sum(int a, int b)
{
return a + b;
}
int result = Sum(1, 2);
Console.WriteLine($"1 加 2 的結果為 {result}");
1 加 2 的結果為 3
函式簽章
如果一種語言允許出現名稱相同的函式,那麽函式簽章將用於識別這些同名函式,以確定具體被使用的是哪一個。函式簽章一般根據函式的名稱,參數的位置和型別等資訊建置。
事實上,函式簽章更妥當的稱呼是方法簽章,因為同名這種情況通常發生在類別中。
在 C# 類別Cannon
中,兩個Attack
方法雖然名稱一樣,但由於參數不同,所以他們的簽章也不同,會被認為是不同的方法。在傳遞不同的參數後,可以確定呼叫其中的哪一個。
// 建立 Cannon 類別的執行個體 cannon
Cannon cannon = new();
// 通過不同的參數,呼叫不同的 Attack 方法
// 呼叫第一個 Attack 方法
cannon.Attack(100);
// 呼叫第二個 Attack 方法
cannon.Attack(100, true);
// 類別 Cannon,表示加農炮
class Cannon
{
// 第一個 Attack 方法,只有一個整數型別參數
public void Attack(int point)
{
Console.WriteLine($"可造成 {point} 點傷害");
}
// 第二個 Attack 方法,有一個整數型別參數和一個布林型別參數
public void Attack(int point, bool critical)
{
Console.WriteLine($"可造成 {point} 點傷害 [暴擊?{critical}]");
}
}
可造成 100 點傷害
可造成 100 點傷害 [暴擊?True]
函式的巢狀呼叫
巢狀呼叫是指在一個函式中呼叫另外一個函式,在實際開發中,這是司空見慣的,經典的案例為,在 C 語言的main
函式中呼叫其他函式。
函式的遞迴呼叫
遞迴呼叫是指一個函式呼叫其自身,當然,呼叫需要符合一定條件,否則函式會嘗試無限的遞迴下去,這會是一場災難。
下面的 C# 函式SumArray
,會將陣列中的非陣列元素視為整數,並計算他們的和,當元素是陣列時,SumArray
將進行遞迴呼叫。
// 將陣列中所有非陣列元素視為整數,並計算他們的和
int SumArray(object[] array)
{
int result = 0;
// 迴圈陣列中的元素,如果是陣列,則呼叫 SumArray 自身
foreach (object item in array)
{
if (item is object[] a)
result += SumArray(a);
else
result += (int)item;
}
return result;
}
// 一個複雜的包含整數的陣列
object[] myArray = new object[] {
new object[] { 1, 2 },
10, 20,
new object[] { 100, 200 },
};
// 呼叫 SumArray 進行計算
int myResult = SumArray(myArray);
Console.WriteLine($"計算結果為:{myResult}");
計算結果為:333