질문 역사
러스트는 객체 지향 언어로부터 메서드 개념을 차용하지만, 이를 다르게 구현합니다: 익숙한 this나 self 대신, 메서드는 명시적으로 self 매개변수를 받습니다. 연관 함수는 다른 프로그래밍 언어의 정적 메서드 대안으로 등장했으며, 특정 값이 아닌 타입과 관련되어 있습니다.
문제
종종 메서드, 연관 함수 및 자유 함수를 혼동하는 경우가 많습니다. self가 있는 메서드를 언제 사용해야 하고, self가 없는 연관 함수를 언제 사용해야 할지 명확하지 않습니다. 가시성, 자동 간접 참조, 소유권 전달과 같은 질문이 있습니다.
해결
러스트에서 메서드는 impl 블록 안에 self/ &self/ &mut self를 첫 번째 매개변수로 선언합니다 (보통 struct나 enum에 대해). 이는 인스턴스에서 호출됩니다: object.method(). 연관 함수(예: new, from)는 동일하게 impl 안에서 선언되지만, 첫 번째 매개변수 self 없이 선언되며, 이중 콜론을 통해 호출됩니다: Type::function().
코드 예제:
struct Point { x: f64, y: f64, } impl Point { // 연관 함수 (생성자) fn new(x: f64, y: f64) -> Self { Self { x, y } } // 메서드: self 요구 fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } let p = Point::new(3.0, 4.0); printf!("{}", p.distance_from_origin()); // 5.0
주요 특징:
::를 통해서만 호출됩니다.연관 함수를 인스턴스를 통해 (점으로) 호출할 수 있는가?
가능하긴 하지만 (예: p.new(1.0, 2.0)), 매우 권장되지 않습니다: 이는 혼란을 초래하며, 연관 함수는 현재 객체에 접근할 수 없고 인스턴스가 무시됩니다. Type::func() 구문을 사용하는 것이 더 좋습니다.
코드 예제:
let p = Point::new(1.0, 2.0); let q = p.new(0.0, 0.0); // 작동하지만 최선의 방법은 아님!
메서드가 비동기적일 수 있는가?
네. 메서드는 자유 함수와 마찬가지로 async 키워드로 선언될 수 있습니다:
impl Foo { async fn do_async(&self) { // ... } }
하나의 impl 블록 안에 메서드와 연관 함수를 모두 선언할 수 있는가?
예 — 모든 조합이 가능합니다. 하나의 타입에 대해 여러 개의 impl 블록을 선언하는 것도 가능합니다.
초보자가 impl 외부에 new 함수를 선언하고 이를 생성자로 사용하려 시도한 후, 실수로 인스턴스를 통해 호출함: p.new(1.0, 2.0).
장점:
빠르게 작동 (컴파일러는 허용함).
단점:
코드가 읽기 어려움, 유지보수가 어려움, self 소유권과 관련된 메서드 사용이 어려움.
모든 메서드와 연관 함수가 엄격히 impl 내부에서 선언되며, 올바른 호출 구문이 사용됨 (Type::new()는 생성자, obj.method()는 동작에 사용됨).
장점:
높은 가독성, 모범 사례에 부합.
단점:
러스트의 관용구에 대한 지식과 구문에 대한 주의가 필요함.