構造体と列挙型

独自の型を定義する方法を学びます。


構造体 (Struct)

定義

filename.ngs
struct Point {
    x: f64
    y: f64
}

struct Person {
    name: str
    age: i32
    email: str
}

インスタンス化

filename.ngs
val p = Point { x: 10.0, y: 20.0 }
val person = Person { name: "Alice", age: 30, email: "alice@example.com" }

フィールドアクセス

filename.ngs
val x = p.x
val name = person.name

// フィールドの変更(var のみ)
var p2 = Point { x: 1.0, y: 2.0 }
p2.x = 10.0  // OK: p2 は var

メソッド

基本的なメソッド

filename.ngs
struct Point {
    x: f64
    y: f64
}

fn Point.distance_to(self: Point, other: Point) f64 {
    val dx = self.x - other.x
    val dy = self.y - other.y
    math.sqrt(dx * dx + dy * dy)
}

fn Point.to_string(self: Point) str {
    "(" + str(self.x) + ", " + str(self.y) + ")"
}

// 使用例
val p1 = Point { x: 0.0, y: 0.0 }
val p2 = Point { x: 3.0, y: 4.0 }

val dist = p1.distance_to(p2)  // 5.0
val s = p1.to_string()          // "(0, 0)"

列挙型 (Enum)

基本的な列挙型

filename.ngs
enum Color {
    Red
    Green
    Blue
}

val c = Color.Red

データを持つ列挙型

filename.ngs
enum Shape {
    Circle(f64)                    // radius
    Rectangle(f64, f64)            // width, height
    Triangle(f64, f64, f64)        // side lengths
}

val area = match shape {
    Shape.Circle(r) => math.PI * r * r,
    Shape.Rectangle(w, h) => w * h,
    Shape.Triangle(a, b, c) => {
        val s = (a + b + c) / 2.0
        math.sqrt(s * (s - a) * (s - b) * (s - c))
    }
}

Result 型

エラーハンドリングのための Result 型:

filename.ngs
enum Result<T, E> {
    Ok(T)
    Err(E)
}

filename.ngs
fn divide(a: f64, b: f64) Result<f64, str> {
    if b == 0.0 {
        Result.Err("ZeroDivision")
    } else {
        Result.Ok(a / b)
    }
}

fn main() void {
    val result = divide(10.0, 3.0)
    
    match result {
        Result.Ok(v) => io.println("Result: " + str(v)),
        Result.Err(e) => io.println("Error: " + e)
    }
}

? 演算子

エラーを上位関数に伝播させる:

filename.ngs
fn parse_int(s: str) Result<i32, str> {
    // 実装は省略
    Result.Ok(42)
}

fn process(s: str) Result<i32, str> {
    val n = parse_int(s)?  // エラーなら即座に return
    Result.Ok(n * 2)
}

ジェネリクス

構造体のジェネリクス

filename.ngs
struct Vec2<T> {
    x: T
    y: T
}

val v1 = Vec2<i32> { x: 1, y: 2 }
val v2 = Vec2<f64> { x: 1.5, y: 2.5 }

関数のジェネリクス

filename.ngs
fn first<T>(arr: List<T>) T {
    arr[0]
}

val n = first(List<i32> { 10, 20, 30 })  // 10
val s = first(List<str> { "a", "b", "c" })  // "a"

Option 型

filename.ngs
enum Option<T> {
    Some(T)
    None
}
filename.ngs
fn find_user(id: i32) Option<User> {
    if id == 1 {
        Option.Some(User { name: "Alice" })
    } else {
        Option.None
    }
}

val user = find_user(1)
match user {
    Option.Some(u) => io.println(u.name),
    Option.None => io.println("Not found")
}