[Rust] async 함수 콜백으로 받기

Vec 등의 정렬 함수를 보면, sort_by 등의 커스텀 정렬은 제공이 된다.

다만 여기서 내가 조금 불편함을 느낀 점은, sort_by에 넘길 클로저에서는 async await 처리를 할 수 없다는 것이다.
그래서 async 버전을 직접 구현해보려고 했다.




원본 코드 (async 아닌 버전)

예시는 버블정렬이다.

fn _bubble_sort_impl<T, F>(array: &mut [T], compare: F)
where
    T: std::cmp::Ord,
    F: Fn(&T, &T) -> std::cmp::Ordering,
{
    let mut last = array.len();

    while 0 != last {
        let mut i = 0;

        while (i + 1) < last {
            match compare(&array[i], &array[i + 1]) {
                std::cmp::Ordering::Less => (),
                std::cmp::Ordering::Greater => utils::swap(array, i, i + 1),
                std::cmp::Ordering::Equal => (),
            }
            i += 1;
        }
        last -= 1;
    }
}

이걸 한번 async 버전으로 바꿔보자.

내가 원하는 호출 형태는 이렇다.

async 블럭 클로저를 받아서 처리하는 것이다.

일단 콜백함수 호출부에 await을 걸어야 한다는 것은 명료하다.

그래야 실행이 되지..

그럼 타입 바운드를 어떻게 걸어야할까?

무작정 Future를 거는건 말이 되지 않는다.

결국 저기서 함수 리턴 타입에 Future를 감싸워야 할 것이다.

그럼 이것만으로 되느냐?


호출이 안된다.
Future 자체는 트레잇이라 사이즈 정보가 없기 때문이다...

어쩔수 없다. 결국에는 Box를 씌워줘야 한다.

근데 그럼 또 Unpin이 필요하다고 하는데, 넣어주도록 하자


자. 이제 이러면 문제들은 다 사라진다.
다 정상적으로 컴파일은 되는데...

문제는

호출부가 조잡해진다는 것이다.
Pin으로 감싸고, 또 Box로 감싸줘야 한다.

감싸는걸 아예 없앨 수는 없지만 간소화는 할 수 있다.
futures 크레이트의 BoxFuture를 사용하는 것이다.

그럼 완성이다.

목표한 바를 전부 이루지는 못했지만, 그래도 이정도면 적당히 쓸수는 있겠다.

디코방에도 이래저래 캐물어봤는데, 이 이상은 어렵다고 한다.

tokio::spawn 같은 함수에서는 Future 클로저를 받을 수 있게 해뒀지만, 이건 해당 클로저에 대해 파라미터나 리턴이 없어서 가능한 경우인 것 같다.