1. 前言
結構(struct) 是 C# 裡一種特別的資料型別,可以把幾個值(甚至不同型別)組合成一個「盒子」。有點像小型 LEGO 組合:你把零件拼起來,最後得到一個方便又精簡的物件。
Struct 跟 class 很像,但有一些差異,通常用在比較「簡單」的情境,不需要 class 那麼強大又「重」的時候。
語法
struct Point
{
public int X;
public int Y;
}
宣告 Point 結構
這個例子裡我們描述了一個平面上的點,座標是 X 跟 Y。
結構通常用在哪?
大多數時候,struct 都是用來裝一些小型、簡單的資料物件,這些物件要很輕量、就是「純資料」。
C# 裡有些標準型別本身就是 struct:
- int、double、bool、DateTime、TimeSpan、decimal、Guid
- 甚至像 ConsoleKeyInfo 或 Point(在圖形函式庫裡)也是 struct
struct 跟 class 的差異
| 比較項目 | 結構(struct) | 類別(class) |
|---|---|---|
| 關鍵字 | |
|
| 儲存型態 | Value Type | Reference Type |
| 存放位置 | Stack(記憶體區域) | Heap(記憶體區域) |
| 傳遞給方法 | 值傳遞(複製一份) | 參考傳遞 |
| 繼承 | 不行(只能實作 interface) | 可以 |
| 能不能是 null | 不行(只能用 Nullable) | 可以 |
| 預設值 | 所有欄位自動初始化為 0 | 只能透過建構子 |
2. 結構的宣告與使用
你可以在 class 裡面或外面宣告 struct:
struct Rectangle
{
public int Width;
public int Height;
}
建立和使用 struct:
Rectangle r;
r.Width = 10;
r.Height = 5;
Console.WriteLine($"面積: {r.Width * r.Height}");
你也可以用建構子來初始化:
struct Point
{
public int X;
public int Y;
// 建構子
public Point(int x, int y)
{
X = x;
Y = y;
}
}
var p = new Point(3, 7);
Console.WriteLine($"點: ({p.X}, {p.Y})");
什麼時候適合用 struct?
- 用來裝小型的資料組合(像是座標、顏色、範圍、日期時間)。
- 當你很在意效能跟記憶體(例如陣列裡有上百萬個點)。
- 當這個物件應該像一個值(copy-paste 會真的複製一份!)。
如果你的物件:
- 很大(欄位很多)。
- 需要繼承結構。
- 常常要用 reference 來改變。
那就不適合用 struct。
3. struct 的特性與「陷阱」
複製
Point p1 = new Point(1, 2);
Point p2 = p1; // 這裡會產生一份「複製品」!
p2.X = 100;
Console.WriteLine(p1.X); // 1 — 沒變!
Console.WriteLine(p2.X); // 100
複製 struct 會產生獨立的副本
預設值是自動給的
Point p; // X 跟 Y 都會自動是 0,就算你沒指定!
可以是 Nullable
如果你想讓 struct 可以存 null,要用特殊的 nullable 語法——型別名稱後面加個問號。這樣你就能把 null 指派給變數。
Point? p = null;
if (p == null)
Console.WriteLine("沒有點");
4. 有自動屬性和方法的 struct
Struct 也可以有方法、屬性、事件,甚至 static 成員。
public struct Range
{
public int Start { get; set; }
public int End { get; set; }
public int Length => End - Start;
public override string ToString() => $"[{Start}..{End}]";
}
範例:複數的 struct
這是一個複數的 struct,有方法跟覆寫 ToString()
struct Complex
{
public double Re;
public double Im;
public Complex(double re, double im)
{
Re = re;
Im = im;
}
public double Abs() => Math.Sqrt(Re * Re + Im * Im);
public override string ToString() => $"{Re} + {Im}i";
}
var z = new Complex(1, 2);
Console.WriteLine(z); // 1 + 2i
Console.WriteLine(z.Abs()); // 2.236...
GO TO FULL VERSION