러스트는 다른 함수형 언어들의 영향을 많이 받아서 함수를 값처럼 전달하고 다른 함수를 리턴하거나 함수를 변수해 할당해 나중에 실행하는 등의 기법을 사용할 수 있다.

클로저(closures)

  • 변수에 저장하거나 다른 함수에 인수로 전달하는 익명함수
  • 일반 함수와 달리 자신이 정의된 범위 내 값들을 캡쳐한다.
  • 구조체를 이용해 값을 캐싱하는 방법을 많이 사용하는데, 이런 기법을 메모제이션(memozation) 혹은 지연 평가(lazy evaluation) 이라고 한다.
  • 모든 클로저는 Fn, FnMut, FnOnce 중 적어도 하나의 trait을 구현한다.
    • FnOnce: 클로저를 선언하는 시점에 소유권을 한번만 가지게 된다. 모든 클로저는 최소 한번은 호출될 수 있으므로 FnOnce trait을 구현한다.
    • FnMut: 값을 가변으로 대여 (클로저의 환경에서 가져온 값을 변경 가능)
    • Fn: 환경에서 값을 불변으로 대여한다.
  • 클로저가 환경에서 가져온 값에 대한 소유권을 갖게 하려면 매개변수 목록 앞에 move키워드를 지정해야 한다.

반복자(iterators)

  • 일련의 원소들을 처리하는 방법
  • 러스트에서 반복자는 지연(lazy) 특성이 있다. 즉 반복자를 실제로 사용하는 메서드를 호출하기 전까지는 아무런 일도 일어나지 않는다.
  • 모든 반복자는 표준 라이브러리에 정의된 Iterator trait을 구현한다.
  • Iterator trait를 구현하려면 반드시 next메서드를 구현해야 한다
  • next 메서드를 호출하는 메서드는 내부적으로 반복자를 소비하므로 소비 어댑터(consuming adaptors)라고 부르기도 한다.
    • 예를 들어 sum메서드는 반복자에 대한 소유권을 가지고 next메서드를 계속 호출해서 아이템을 순회하므로 반복자를 소비한다고 할 수 있다.
  • Iterator trait에 선언된 다른 메서드인 반복자 어댑터(iterator adaptor)는 후출한 후의 결과를 얻으려면 소비어댑터 메서드중 하나를 호출해야 한다.
    • 예를들어 아래 구문에서 collect()가 반복자를 소비하는 소비 어댑터이다.
    • let v2: Vec<_> = vec![1, 2, 3].iter().map(|x| x + 1).collect();
  • Iterator의 filter 메서드는 반복자로부터 각 아이템을 가져와 boolan값을 리턴하는 클로저에게 전달한다. 클로저가 true를 리턴하면 그 값은 filter 메서드가 생성하는 반복자에 추가되고 false를 리턴하면 추가되지 않는다.

For loop VS Iterator

  • 반복자는 러스트의 무비용 추상화(zero-cost abstractions) 기능중 하나이다.
  • 추상화를 사용한다고 해서 추가적인 런타인 오버헤드가 발생하지 않는다(!)
  • 러스트의 최적화는 결과 코드의 효율성을 극대화 한다. 따라서 런타임 성능을 손실하지 않으면서도 더 고수준의 코드를 작성할 수 있다.