rust

[Rust] 5. struct에 대하여

승딱 2023. 1. 31. 23:13
반응형

https://doc.rust-lang.org/book/ch05-01-defining-structs.html

링크를 복습하면서 정리하는 글이며 js 나 solidity 를 사전지식으로 하는상황에서 비슷한 부분은 정리하지 않은 글이다.

Struct Type

> 기본구조

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

- 다양한 타입의 필드를 가지고 있고 순서에 상관 없이 필드에따라 값을 지정해줄수 있다.

 

> 인스턴스 생성 과 syntax

let user1 = User {
  active: true,
  username: String::from("someusername123"),
  email: String::from("someone@example.com"),
  sign_in_count: 1,
};

- 위와같이 해당 타입으로 인스턴스를 생성하수 있다.

- 인스턴스 생성자 함수를 사용하는 경우 같은 네이밍은 shortcut 을 사용할수 있다.

- 다른인스턴스를 바탕으로 생성하는경우 .. syntax 를 사용할수 있으며 구문특징은 js 의 spread syntax(...) 와 같다.

- 다른인스턴스를 바탕으로 생성하는경우 다른인스턴스에 힙데이터가 존재한다면 소유권 이전이 일어나면 이후에 해당인스턴스는 유효하지 않을수 있다는 점은 유의해야한다.

> 인스턴스 접근 및 변경

fn main() {
    let mut user1 = User {
        ...
    };

    user1.email = String::from("anotheremail@example.com");
}

- dot notation 으로 접근 및 변경 이 가능 하지만 변경할때는 역시 인스턴스 생성시 변수는 mut 키워드로 생성되어야한다.

> tuple struct

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);


fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
    let tup: (i32, f64, u8) = (500, 6.4, 1);
}

- tuple struct 형태로 field 의 name 없이 사용하는 sturct 형태이며 tuple처럼 구조분해하거나 dot notation 으로 index 로 접근할수있다.

> unit-like struct

struct AlwaysEqual;

fn main() {
    let subject = AlwaysEqual;
}

- unit-like struct 형태로 filed 자체가 존재하지 않는 struct 형태이다 어떤 목적으로 쓰이는지는 잘모르겠는데 ch10 에서 trait 과 관련해서 사용되는 부분이 있다고 하니 그때한번 봐야겠다.

> reference in filed type

struct User {
    active: bool,
    username: &str,
    email: &str,
    sign_in_count: u64,
}

- filed type에 reference 를 사용할수는 있지만 그럴경우 lifetime에 대한 표시가 있어야 한다고한다. 그부분도 ch10 에 있다고 하니 그때다시 봐야겠다.

> debug trait

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!("rect1 is {:?}", rect1); //rect1 is Rectangle { width: 30, height: 50 }
    println!("rect1 is {:#?}", rect1); 
    // rect1 is 
  Rectangle {
    width: 30,
    height: 50,
  }
}

- #[derive(Debug)] 이부분을 trait 이라고 하는거 같다.

- 원시유형과 다르게 구조체는 Display 하기 위한 implementation 을 가지고 있지 않아 trait 을 통해 Debug할수 있는 implemtation 을 상속받아야 print 할수 있게된다.

- :#? :? 와 같은 문자를 통해 디버그 format 을 지정할수 있다.

> method

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

- impl 키워드를 통해 원하는 구조체의 메서드를 생성할수도 있다. 

- 메서드의 첫번째인자로는 메서드를 호출하는 인스턴스를 self 로 칭하며 사용할수 있고 참조자형태로 주로 사용한다.

- 메서드는 소유권을 가져올수도 있고 borrow 해서 사용할수도 있으며 mutable 하게 borrow 할수도 있다. 즉 self , &self, &mut self  와 같은 형태로 사용가능하니 필요에 맞게 설정할수 있다.

- 다만 self 그대로 사용하는 경우 소유권이 move 됨으로 이후 origin instance 를 사용할수 없으니 주의해야한다.

- 더많은 인자를 필요로 하는경우 self 이후로 순서대로 받아 사용하면 된다.

> associated function

impl Rectangle {
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }
}

- 위와같이 self를 인자로 사용하지 않는 함수도 impl 키워드를 통해 struct에 정의 할수 있는데 이런 함수는 method 라고 부르지 않고 associated function 이라고 부른다.

- associated function 은 self 를 첫번째 인자로 받아 사용하지는 않지만 함수안에서 Self 라는 키워드는 사용할수 있는데 여기서 Self 는 이는 해당 struct type 을 지칭한다.

- method 는 인스턴스에 dot notation 으로 접근해서 사용했지만 associated function은 해당 타입에 :: syntax 를 통해 접근해서 사용할수 있다.

- 잘알고 있는 예시로 String::from("asdf") funtion 이 있는데 이처럼 struct::funcname(param) 형태로 사용하면된다.

- 위의 예시의 사용은 lec rect = Rectangle::squre(3)

 

> 잘 이해안가는 부분

Rust doesn’t have an equivalent to the -> operator; instead, Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.

Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:

p1.distance(&p2);
(&p1).distance(&p2);