5.3. 메서드 문법

메서드

객체에서 사용하듯이 구조체에 메서드를 정의하는 것이 가능하다.

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

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

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

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}

구조체 컨텍스트에 정의한다.
시작은 impl이라는 구현 블록을 만드는 것이다.
첫 매개변수는 항상 self이다.
이후에는 self로 인스턴스에 접근하여 동작하도록 코드를 짠다.

여기에서 &selfself: &Self를 줄인 것이다.
impl 블록의 대상이 되는 것의 별칭이 바로 Self이다.
메서드 역시 소유권을 가져오는 것이 가능하기에, 빌려오고만 싶다면 반드시 &를 사용하라.
그냥 self만 사용하는 경우는 대체로 무언가로 변환하고 이후로 원본 인스턴스의 사용을 막을 때이다.

impl Rectangle {
    fn width(&self) -> bool {
        self.width > 0
    }
}

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

    if rect1.width() {
        println!("The rectangle has a nonzero width; it is {}", rect1.width);
    }
}

필드 이름과 동일한 메서드를 만드는 것도 가능하다.
()를 붙이는 것으로 러스트는 메서드인지 필드인지 판단한다.
이름을 같게 하는 경우는 getter를 구현할 때이다.
필드는 비공개하고 읽기전용으로만 만들 때 유용하다.

-> 연산자

C에 있는 구조체 포인터 -> 연산자는 러스트에 존재하지 않는다.
자동참조 및 역참조 기능으로 알아서 러스트에서 원하는 값을 가져올 수 있기 때문이다.

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

위 코드는 동일하다.
러스트에서는 명확하게 파악 가능한 코드 환경에 놓여 있기에 이게 가능하다.

외부의 매개변수를 가지는 메서드

사각형 넓이를 비교하는 메서드를 만들어보자.

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

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

외부의 값을 받아 수행하려면 이렇게 한다.

연관 함수

기본적으로 impl 안에 구현된 함수들은 연관 함수(assosiatied function)이라고 부른다.
self가 필요 없어서 메서드로 분류되지 않는 함수이다.
연관 함수는 구조체의 새 인스턴스를 반환하는 생성자로 자주 활용된다.
흔히 new라는 이름으로 만들어진다.
new는 키워드가 아니고 그저 생성자에 지나지 않는다.
Pasted image 20240501143151.png
square라는 함수는 self를 가지지 않는다.
또한 Self를 반환해준다.
이를 통해 생성자 역할을 해주는 것이다.

let rect3: Rectangle = Rectangle::square(22);

이제 이러한 코드가 가능해진다.
확실히 보이도록 타입도 명시해줬다.
안 해도 상관은 없다.

여러 개의 impl을 둘 수 있다.
물론 하나로 해도 상관 없다.
이렇게 하면 나중에 제네릭이나 트레이트를 할 때 유용하게 사용할 수 있다.