프로그래밍 언어/[Rust]

[Rust] Rust Functions

swc0317 2025. 2. 9. 16:51
728x90
반응형
프로그래밍 언어에서의 함수란?

 

함수는 프로그래밍에서 특정 작업을 수행하는 코드 블록으로, 

 

1. 재사용 가능하고 

 

2. 모듈화 된 단위입니다.

 

3. 함수를 사용하면 코드의 가독성 유지보수성이 높아지고, 

 

4. 중복 코드를 줄일 수 있어 효율적입니다.

 

당연히 Rust에서도 함수를 구현할 수 있는 문법을 제공합니다.

 

C, C++의 함수

 

 

int add(int a, int b){
 ..
}

 

C, C++에서 "add" 라는 함수를 정의하면 위와 같이 정의합니다.

 

이때 이 "add" 라는 함수의 행동을 정의하고 싶다면 { } 사이에 원하는 구문을 삽입합니다.

 

예를 들어 

 

return a + b;

 

와 같은 구문을 넣을 수 있을 겁니다.

 

이때, return 하고자 하는 값의 type을 함수 이름 앞에, 

 

함수의 연산에 사용될 인자를 함수 이름 뒤 괄호에 포함시킵니다.

 

즉, 구조상으로 이게 함수라는 걸 아는 거지,

 

명시적으로 이게 함수다, 라고 말하는 표현법이 없습니다.

 

 

Rust의 함수

 

Rust는 "fn" 예약어를 통해 이게 함수라는 걸 명시합니다.

 

예시로, 두 개의 unsigned 32bit 정수를 받고, boolean 값을 return 하는

 

함수를 정의해보겠습니다.

 

fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
    if rhs == 0 {
        return false;
    }

    lhs % rhs == 0
}

 

"is_divisible_by" 라는 이름의 함수로 두 개의 u32 인자 lhs, rhs를 받고

 

boolean 값을 return 하는 함수입니다.

 

divide_by_zero error를 피하기 위해 분모가 0인지 확인하고,

 

lhs % rhs == 0을 return 하는 모습입니다.

 

왜 함수 block 마지막에 return과, 세미 콜론이 없냐면,

 

[Rust] Expression

Expression Rust를 포함하고, 여러 프로그래밍 언어의 소스코드는 여러 구문으로  구성되어있습니다. 예를 들어, C++의 swap 연산은 아래와 같습니다. #include // 템플릿을 사용한 swap 함수template void sw

swc0317.tistory.com

 

위의 포스트를 참조해 주세요.

 

 

Rust의 void 형 return

 

 

C/C++에서 함수 내부에서 return 하는 값이 없다면

 

void 예약어를 통해 "return 하지 않는다"를 명시합니다.

 

void print(string S){
..
}

 

Rust에선 void 형이 없습니다. 대신 () 라는, 빈 튜플을 return 하는 걸

 

void 형으로 명시합니다.

 

관련 내용은 아래 포스트를 참조해 주세요.

 

[Rust] 기본 골자

Rust의 타입형들  Rust learn by example Primitives - Rust By ExampleRust provides access to a wide variety of primitives. A sample includes: Signed integers: i8, i16, i32, i64, i128 and isize (pointer size) Unsigned integers: u8, u16, u32, u64, u128

swc0317.tistory.com

 

또는, 의도적으로 누락할 수 있습니다.

 

fn fizzbuzz(n: u32) -> () {
    if is_divisible_by(n, 15) {
        println!("fizzbuzz");
    } else if is_divisible_by(n, 3) {
        println!("fizz");
    } else if is_divisible_by(n, 5) {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}


fn fizzbuzz_to(n: u32) {
    for n in 1..=n {
        fizzbuzz(n);
    }
}

 

위 함수는 1부터 n까지 fizzbuzz라는 함수를 실행하는 함수입니다.

 

이때 return이 없다는 걸 위처럼 -> ()를 누락할 수도 있고,

 

명시할 수도 있습니다.

 

 

Associated function & Method

 

Method, 메소드는 파이썬을 해보셨다면 익숙하실겁니다.

 

    def block_read(self, address):
        # 읽어올 32byte(8개의 워드)를 담을 리스트
        # address엔 tag 24bit + cache idx 3bit을 포함한 상위 27비트가 담겨있음.
        # 하위 2bit는 32bit data aligned를 이용하므로
        # 4의 배수 단위로 0 ~ 28까지 메모리를 접근해주면 OK.
        data_block = []
        for offset in range(0, 32, 4):
            word_address = address + offset
            data_block.append(self.mem[word_address])
        return data_block

 

위의 함수는 메모리를 block 단위로 읽어오는 함수입니다.

 

이때, 현재 object 타입에 정의된 "특정한" 함수를 

 

현재 객체에 실행하고 싶다면 "." 을 통해 명시합니다.

 

즉, 메소드란 어떤 객체가 특정한 타입을 가질 때, 명시된

 

연산을 인자로 삽입할 필요없이 "현재 객체에 연산하라"를

 

함축합니다.

 

Associated Function은 Method와 유사하게,

 

"특정 타입에 연관된 함수" 입니다. 그러나,

 

함수 연산에 객체를 받지않습니다. 즉 

 

둘의 명시적인 차이는 인자로 self가 포함되느냐 아니냐 입니다.

 

예시입니다.

 

struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    fn area(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;
        ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;
        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }

    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p2.x += x;
        self.p1.y += y;
        self.p2.y += y;
    }
}

 

먼저 두 개의 double precision 소수 타입으로 구성된 Point 구조체와,

 

이 Point 타입 두 개로 이루어진 Rectangle 구조체입니다.

 

이때 impl 예약어 아래 정의된 함수들은, 

 

앞서말한 Associated function & Method로,

 

해당 구조체에 특정한 연산을 할 수 있는 함수들을

 

구현해놓은 Implemetation block 입니다.

 

이때 origin, new 함수들은 self가 포함되지 않으니,

 

associated function, 

 

area, perimeter, traslate은 인자에 self가 포함되니,

 

method 함수입니다. 단순히 

 

인자로 구분하는 것 뿐만 아니라 실제 사용법도 다릅니다.

 

아래는 assoicated function을 사용하는 예제입니다.

 

fn main() {
    let rectangle = Rectangle {
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0), 
    };
 }

 

보시면 각 Point 인자들을 정의하기 위해 origin, new 함수를 쓰되,

 

특정한 객체없이 함수를 사용합니다.

 

아래는 Method 함수를 사용하는 예재입니다.

 

    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());
    square.translate(1.0, 1.0);
    pair.destroy();

 

보시면 특정 타입의 실체 객체가 있어야 사용할 수 있는 함수들입니다.

 

 

728x90
반응형

'프로그래밍 언어 > [Rust]' 카테고리의 다른 글

[Rust] ToolChain Nightly  (1) 2025.02.15
[Rust] Closures  (0) 2025.02.09
[Rust] Expression  (0) 2025.01.07
[Rust] Type Conversion  (0) 2025.01.07
[Rust] Types  (1) 2025.01.03