5. 연관된 데이터를 구조체로 다루기

5.1 구조체 정의와 초기화

 
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, };
 

구조체 갱신법

let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername567"), active: user1.active, sign_in_count: user1.sign_in_count, };
아래와 같다.
let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername567"), ..user1 };
 

튜플 구조체

struct Color(i32, i32, i32); struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0);
  • blackorigin은 서로 다른 자료형이다.
 

유사 유닛 구조체

  • () 와 같이 아무런 데이터가 없는 구조체도 작성 가능. 트레일을 사용할 때 유용.
 

구조체의 소유권

  • 구조체 안에서 참조자를 사용할 경우 반드시 life time을 지정해 주어야 한다.
struct User { username: &str, email: &str, sign_in_count: u64, active: bool, } fn main() { let user1 = User { email: "someone@example.com", username: "someusername123", active: true, sign_in_count: 1, }; }
error[E0106]: missing lifetime specifier --> | 2 | username: &str, | ^ expected lifetime parameter error[E0106]: missing lifetime specifier --> | 3 | email: &str, | ^ expected lifetime parameter
 

5.2. 구조체를 이용한 예제 프로그램

  • 사각형의 넓이를 구해보자
struct Rectangle { length: u32, width: u32, } fn main() { let rect1 = Rectangle { length: 50, width: 30 }; println!("rect1 is {}", rect1); } fn area(rectangle: &Rectangle) -> u32 { rectangle.length * rectangle.width }
error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied
  • trait: 일종의 protocol 이나 interface 느낌인데, 자료형이 꼭 해야하는 일을 명시해 준 것이라 생각하면 편할 듯.
  • println! 매크로로 { } 를 사용하여 무언가를 출력하려면 std::fmt::Display 트레잇을 구현해야 한다.
  • println! 매크로로 디버그를 위해서 {:?} 를 사용하려면 std::fmt::Debug 트레잇을 구현하거나 구조체 선언부 앞에 #[derive(Debug)] 를 사용한다.
 
#[derive(Debug)] struct Rectangle { length: u32, width: u32, } fn main() { let rect1 = Rectangle { length: 50, width: 30 }; println!("rect1 is {:?}", rect1); }
 

5.3 메소드 문법

  • 메소드: 구조체 안에 들어있는 함수.
#[derive(Debug)] struct Rectangle { length: u32, width: u32, } impl Rectangle { fn area(&self) -> u32 { self.length * self.width } } fn main() { let rect1 = Rectangle { length: 50, width: 30 }; println!( "The area of the rectangle is {} square pixels.", rect1.area() ); }
  • impl 블록에서 구조체의 메소드를 정의할 수 있음. 첫 번째 인자는 반드시 self.
 

연관 함수

  • static 함수나 class 메서드 같은 역할. 호출할 때는 . 대신에 ::를 사용.
impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle { length: size, width: size } } }
  • 위의 함수는 let sq = Rectangle::square(3); 처럼 호출 가능.
 
 
💡
. vs :: . 은 인스턴스에 묶인 함수, 즉 메소드를 호출한다. ::은 타입이나 모듈에 있는 함수나 이름을 의미한다.