구조체
Wave 언어의 구 조체는 사용자 정의 데이터 타입을 선언하기 위한 문법 요소이며, 서로 다른 타입의 값을 하나의 집합으로 묶어 표현할 수 있도록 설계되어 있습니다. 구조체는 값 타입(value type)으로 동작하며, 모든 필드는 명시적으로 타입을 가져야 하고, 모든 필드의 초기값은 구조체 생성 시 반드시 제공되어야 합니다.
구조체 선언 문법
구조체는 struct 키워드를 사용하여 선언합니다. 구조체의 이름은 파스칼 표기법(PascalCase)을 사용하며, 구조체 본문에는 하나 이상의 필드를 선언할 수 있습니다. 필드는 이름: 타입; 형식으로 작성합니다. 모든 필드 선언 뒤에는 세미콜론이 필요합니다.
struct Box {
size: i32;
weight: f32;
}
구조체 선언 시 필드의 순서는 메모리 배치 순서와 동일하게 사용됩니다. 구조체 내부에는 필드 선언만 허용되며, 함수나 메서드는 포함될 수 없습니다.
구조체 생성 문법
구조체는 구조체 이름을 이용한 리터럴 형식으로 생성합니다. 구조체 리터럴은 StructName { 필드명: 값; ... } 형식을 사용하며, 정의된 모든 필드는 반드시 초기화해야 합니다. 초기화 시 필드의 순서는 선언 순서와 동일할 필요는 없습니다.
var b: Box = Box {
size: 42;
weight: 10.5;
};
초기화 시 누락된 필드가 존재하면 컴파일 오류가 발생합니다. 초기화 시 제공하는 값의 타입은 구조체에서 정의한 타입과 정확히 일치해야 하며, 암묵적 변환은 허용되지 않습니다.
구조체 필드 접근 문법
구조체의 필드는 점 표기법(dot notation)을 통해 접근합니다. 필드 접근은 읽기 연산과 쓰기 연산 모두에 동일하게 사용되며, 존재하지 않는 필드 이름을 사용하면 컴파일 오류가 발생합니다.
println("Size: {}", b.size);
println("Weight: {}", b.weight);
구조체 변수는 값 타입으로 동작하기 때문에 구조체 전체를 대입하거나 함수 인자로 전달할 때 구조체의 모든 필드가 복사됩니다.
구조체 메서드 정의 문법
Wave 언어는 구조체 자체 안에 메서드를 포함하지 않으며, proto 키워드를 사용하여 구조체에 메서드를 연결합니다. proto 블록은 특정 구조체에 속한 함수 집합을 선언하는 영역입니다. proto 내부의 함수는 구조체 인스턴스를 가리키기 위해 첫 번째 매개변수로 self를 사용합니다. self는 구조체 전체 값을 전달받으며, 이는 값 복사 방식으로 처리됩니다.
proto Box {
fun print(self) {
println("size={}, weight={}", self.size, self.weight);
}
fun added_size(self, x: i32) -> i32 {
return self.size + x;
}
}
proto 블록은 구조체 선언과 같은 파일에 위치할 필요는 없으며, 여러 proto 블록을 통해 동일한 구조체에 추가적인 메서드를 정의할 수 있습니다. 메서드 호출은 일반적인 함수 호출과 동일하며, 구조체 인스턴스를 대상으로 점 표기법을 이용 하여 호출합니다.
b.print();
var n: i32 = b.added_size(5);
함수 인자로서의 구조체 사용
구조체는 함수 인자로 전달될 때 값 복사 방식으로 처리됩니다. 구조체 내부의 필드를 수정하더라도 호출한 쪽의 구조체 인스턴스에는 영향을 미치지 않습니다.
fun calc(box: Box) -> i32 {
return box.size * 2;
}
함수에서 구조체를 반환할 경우에도 동일하게 값 복사가 발생합니다.
중첩 구조체(Nested Struct)
Wave에서는 구조체 내부의 필드 타입으로 다른 구조체를 사용할 수 있습니다. 구조체는 완전한 타입이기 때문에 하나의 구조체가 다른 구조체를 포함하는 형태로 중첩하여 사용할 수 있습니다.
struct Position {
x: i32;
y: i32;
}
struct Player {
name: str;
pos: Position;
}
중첩된 구조체는 점 표기법을 연속으로 사용하여 내부 필드를 접근할 수 있습니다.
var p: Player = Player {
name: "Alice";
pos: Position { x: 10; y: 20; };
};
println("Player X: {}", p.pos.x);
println("Player Y: {}", p.pos.y);
구조체 리터럴 내부에서 또 다른 구조체 리터럴을 중첩하여 작성할 수 있으며, 이 경우에도 모든 필드 초기화 규칙이 동일하게 적용됩니다.
구조체 배열
구조체는 배열의 원소 타입으로도 사용할 수 있습니다. 배열의 문법은 array<타입, 길이> 형식을 사용하며, 구조체 타입을 그대로 배열의 요소로 지정할 수 있습니다.
var players: array<Player, 3> = [
Player { name: "A"; pos: Position { x: 1; y: 2; }; },
Player { name: "B"; pos: Position { x: 3; y: 4; }; },
Player { name: "C"; pos: Position { x: 5; y: 6; }; }
];
구조체 배열의 각 원소에 접근할 때는 먼저 배열 인덱스를 사용하고, 이후 점 표기법으로 구조체 필드를 접근합니다.
println("Second Player X: {}", players[1].pos.x);
구조체의 기본 연산 가능 여부
Wave의 구조체는 사용자 정의 타입이기 때문에 산술 연산이나 비교 연산 등에 자동으로 참여할 수 없습니다. 구조체의 동등성 비교나 해싱, 정렬 등을 수행하려면 proto 블록을 통해 관련 기능을 직접 구현해야 합니다. 구조체끼리의 연산자는 Wave 언어에서 자동 제공되지 않으며, 연산이 필요한 경우 반드시 함수나 메서드로 정의해야 합니다.