【C#學習筆記】04《整數與浮點數》
【C#學習筆記】06《字串與字元》
元組(Tuple)是用來回傳或儲存多個值的寫法技巧,忽略(Discard)則是丟棄特定的Tuple值。
在C#7.0之前,因為還沒有相關的語法,如果要回傳多個值,通常會使用out參數,或包裝成class/struct。
雖然這樣做也可以,但在多參數的情況下,程式碼會變得冗長。而使用class/struct,雖然可讀性高,但變成次要資料也必須得用class/struct包起來
// tuple and discard, supported in C# 7.0 and later
//Before C# 7.0
void GetMinMaxOld(int a, int b, out int max, out int min)
{
max = Math.Max(a, b);
min = Math.Min(a, b);
}
//call
int max_old;
int min_old;
GetMinMaxOld(3, 10, out max_old, out min_old);
Console.WriteLine($"max_old = {max_old}");
Console.WriteLine($"min_old = {min_old}");
在C#7.0之後,多了Tuple語法,程式碼就會簡潔許多。
// C# 7.0 and later
int GetMax(int a, int b) => a > b ? a : b;
// C# 7.0 and later supports tuples, so we can return both max and min in a single method
(int max, int min) GetMaxMin(int a, int b) => a > b ? (a, b) : (b, a);
var (max, min) = GetMaxMin(5, 10);
Console.WriteLine($"Max: {max}, Min: {min}");
var k = GetMaxMin(7, 17);
Console.WriteLine($"Max: {k.max}, Min: {k.min}");//recommended
Console.WriteLine($"Max: {k.Item1}, Min: {k.Item2}");//unrecommended, less readable
Tuple主要用來「一次回傳或儲存多個值」,是一種輕量級的資料結構,能將多個不同型別的值組合在一起。
格式:
//(型別 名稱, 型別 名稱, .....)Tuple名稱
//宣告
(int x, int y) position;//一個包含x與y的Tuple-position
//賦值
position = (10, 20);
//取值
Console.WriteLine(position.x);
Console.WriteLine(position.y);
遊戲開發時,我們要取得玩家名稱、等級、HP,如果只使用一般的return,一次只能回傳一個值。我們改成使用Tuple:
// 回傳一個 Tuple
// Tuple 內包含:name、level、hp 三個值
(string name, int level, float hp) GetPlayerInfo(string playerName, int playerLevel, float playerHp)
{
return (playerName, playerLevel, playerHp);// 將三個值打包成 Tuple 回傳
}
// 呼叫函式
// 回傳值會存進 player
var player = GetPlayerInfo("Player1", 10, 100.0f);
// 使用 Tuple 內的名稱存取資料
Console.WriteLine($"Name: {player.name}, Level: {player.level}, HP: {player.hp}");
取得物件座標:
(float x, float y) GetPosition() => (10.5f, 20.5f);
var (x, y) = GetPosition();
Console.WriteLine($"X: {x}, Y: {y}");//X: 10.5、Y: 20.5
void EasySample(int a, int b)
{
switch(a , b)
{
case(> 0, > 0) when a == b:
Console.WriteLine("same");
break;
case(> 0, > 0):
Console.WriteLine($"first: {a}, second: {b}");
break;
default:
Console.WriteLine($"not valid");
break;
}
}
EasySample(5, 5);
EasySample(5, 10);
Discard用於忽略Tuple中的特定值
var (maxValue, _) = GetMaxMin(3, 8);// We only care about the max value, so we discard the min value using '_'
Console.WriteLine($"Max: {maxValue}");
_ = GetMaxMin(15, 5); // We don't care about the result, just want to call the method
GetMaxMin(5, 10);// We can also ignore the result of a method that returns a tuple
解構是指將Tuple中的元素「拆解」並賦值給個別獨立的變數。這讓程式碼讀起來更像是在處理一般變數,而不是在操作一個物件。
上述提到的Discard其實也是解構的一種行為。
(int hp, bool isDead) TakeDamage(int hp, int damage)
{
hp -= damage;
return (hp, hp <= 0);
}
var result = TakeDamage(100, 30);
int hp = result.hp;
bool dead = result.isDead;
Console.WriteLine(hp);
Console.WriteLine(dead);
解構最酷的應用之一,就是不需要暫存變數temp 就能交換兩個變數的值:
int a = 5, b = 10;
(a, b) = (b, a);
Console.WriteLine($"a: {a}, b: {b}");
「這雖然使用了Tuple的語法結構,但編譯器會優化它,不會真的產生Tuple物件,是目前C#最推薦的數值交換方式。」
「總結來說,Tuple是C#提供給開發者的『輕量資料組合工具』。它並不是要取代Class,而是讓我們在處理『暫時性、小規模、關聯性強』的資料時,可以避免為了單純傳遞幾個值而額外建立型別。透過Tuple與解構的搭配,程式碼通常能變得更簡潔,也更適合表達『多值回傳』這類情境。不過,Tuple更偏向資料傳遞工具;當資料開始具有明確語意、複雜邏輯、長期維護需求,或需要作為公開API與系統核心模型時,使用 Class、Record或其他明確型別,通常會有更好的可讀性與擴充性。」