구조체의 기본
구조체란 0 개 이상의 필드와 메서드로 구성된, 이름을 가진 하나의 데이터 구조를 의미함. 오늘날 사람들에게 가장 친숙한 언어 중 하나인 자바에 비유하면 구조체란 클래스이고, 필드는 변수, 메서드는 메서드라 말할 수 있음. 필드는 각각 서로 다른 데이터 타입을 가질 수 있음.
구조체의 정의와 사용
구조체는 아래와 같이 정의됨.
struct User {
username : String,
email: String,
sign_in_count: u64,
active: bool,
}
그리고 아래와 같이 사용됨. 보다시피 구조체에 선언된 필드 순서와 생성 시의 필드 순서는 관계없음. 오로지 필드 이름으로 매핑.
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
println!("{}", user1.email);
구조체 인스턴스 역시 임뮤터블 or 뮤터블로 생성할 수 있으며, 임뮤터블 인스턴스의 필드를 변경하려 하면 컴파일 에러 발생. 그리고, 구조체 인스턴스가 뮤터블로 생성되면 그 인스턴스의 모든 필드가 뮤터블이고, 반대로 임뮤터블로 생성되면 모든 필드가 임뮤터블임. 특정 필드만 임뮤터블/뮤터블로 지정하는 것은 불가능.
아래와 같이 뮤터블로 생성하여야 필드를 변경할 수 있음.
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("someone2@example.com");
구조체를 생성할 때마다 구조체 코드를 작성하기는 번거로움. 아래와 같은 구조체 인스턴스 생성 함수를 선언하고 사용할 수 있음.
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
아래와 같이 사용.
let mut user1 = build_user(String::from("someone@example.com"), String::from("someusername123"));
인스턴스 생성 함수의 파라미터와 구조체 필드명이 동일하면 파라미터-필드를 자동으로 매핑해줌. 좀 더 편하게 작성할 수 있음. 아래가 그 예시.
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
파라미터 email, usrename 가 구조체의 필드명과 같기 때문에 알아서 구조체의 해당 필드로 데이터를 세팅함.
다른 구조체의 값을 기본값으로 사용할 수도 있음.
let user1 = build_user(String::from("someone@example.com"), String::from("someusername123"));
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
더 간단하게 아래의 방법도 가능. email, username 만 지정하고 나머지는 user1 의 값을 그대로 사용.
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername"),
..user1
};
튜플 구조체
튜플과 유사한 형태로 구조체를 정의하고 사용할 수도 있음. 이를 튜플 구조체라 함. 그룹화된 데이터 각각의 이름이 중요하지 않을 때, 하지만 그룹으로 묶이면서 하나의 의미를 가진 데이터가 되는 경우 이런 구조체가 유용하게 사용될 수 있음.
아래와 같이 정의.
struct Color(i32, i32, i32, String);
struct Point(i32, i32, i32, String);
아래와 같이 사용. 각 인스턴스의 필드는 튜플과 마찬가지로 .{index} 방식으로 접근할 수 있음.
let black = Color(0, 0, 0, String::from("black"));
let origin = Point(0, 0, 0, String::from("x"));
println!("{}", black.0}
println!("{}", black.1}
Unit-Like 구조체
필드가 전혀 존재하지 않는 튜플도 있음. 이를 Unit-Like 구조체라 하는데, 어떤 타입에 특성을 구현할 때 사용할 수 있음. 여기서는 자세히 다루지 않고, 후에 타입의 특성을 다룰 때 다시 등장.