ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Rust] 5. struct에 대하여
    rust 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);
Designed by Tistory.