함수형 스타일의 프로그래밍은 대개 아래의 것들을 포함 (아래의 것들을 closure라고 한다.)함수를 값처럼 인수로 넘기는 것, 다른 함수들에서 결괏값으로 함수들을 반환하는 것, 나중에 실행하기 위해 함수를 변수에 할당하는 것#[derive(Debug, PartialEq, Copy, Clone)]
enum ShirtColor {
Red,
Blue,
}
struct Inventory {
shirts: Vec<ShirtColor>,
}
impl Inventory {
fn giveaway(&self, user_preference: Option<ShirtColor>) -> ShirtColor {
user_preference.unwrap_or_else(|| self.most_stocked())
}
fn most_stocked(&self) -> ShirtColor {
let mut num_red = 0;
let mut num_blue = 0;
for color in &self.shirts {
match color {
ShirtColor::Red => num_red += 1,
ShirtColor::Blue => num_blue += 1,
}
}
if num_red > num_blue {
ShirtColor::Red
} else {
ShirtColor::Blue
}
}
}
fn main() {
let store = Inventory {
shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue],
};
let user_pref1 = Some(ShirtColor::Red);
let giveaway1 = store.giveaway(user_pref1);
println!(
"The user with preference {:?} gets {:?}",
user_pref1, giveaway1
);
let user_pref2 = None;
let giveaway2 = store.giveaway(user_pref2);
println!(
"The user with preference {:?} gets {:?}",
user_pref2, giveaway2
);
}
Option<T>의 unwrap_or_else 메서드Option<T>의 Some 배리언트에 저장되는 타입과 동일하며, 지금의 경우 ShirtColor입니다.self Inventory 인스턴스의 불변 참조자를 캡처하여 우리가 지정한 코드와 함께 이 값을 unwrap_or_else 메서드에 넘겨줍니다.

let example_closure = |x| x;
let s = example_closure(String::from("hello"));
let n = example_closure(5);
세 가지 방식으로 자신의 환경으로부터 값을 캡처할 수 있는데, 이는 함수가 매개변수를 취하는 세 가지 방식과 직접적으로 대응됩니다: 캡처된 값이 쓰이는 방식에 기초하여 캡처할 방법을 결정

매개변수 리스트 전에 move 키워드를 사용할 수 있습니다.use std::thread;
fn main() {
let list = vec![1, 2, 3];
println!("Before defining closure: {:?}", list);
thread::spawn(move || println!("From thread: {:?}", list))
.join()
.unwrap();
}
시작 단계에서부터 환경으로부터 아무 값도 캡처하지 않기 (1)캡처된 값을 이동시키지도 변형시키지도 않기 (2)캡처된 값을 변형하기 (3)캡처된 값을 클로저 밖으로 이동시키기 (4)클로저가 환경으로부터 값을 캡처하고 다루는 방식(위 4가지)은 이 클로저가 구현하는 트레이트에 영향을 줌클로저가 구현한 트레이트는 함수와 구조체가 사용할 수 있는 클로저의 종류를 명시할 수 있는 방법FnOnce캡처된 값을 본문 밖으로 이동시키는 클로저(4)에 대해서는 FnOnce만 구현되며 나머지 Fn 트레이트는 구현되지 않는데, FnMut본문 밖으로 캡처된 값을 이동시키지는 않지만, 값을 변경할 수는 있는 클로저(3)에 대해 적용Fn캡처된 값을 본문 밖으로 이동시키지 않고 캡처된 값을 변경하지도 않는 클로저(2)는 물론, 환경으로부터 아무런 값도 캡처하지 않는 클로저(1)에 적용 
환경으로부터 값을 캡처할 필요가 없다면, Fn 트레이트 중 하나를 구현한 무언가가 필요한 곳에 클로저 대신 함수 이름을 사용할 수 있습니다. Option<Vec<T>>의 값 상에서 unwrap_or_else(Vec::new)를 호출하여 이 값이 None일 경우 비어있는 새 벡터를 얻을 수 있습니다.원본 데이터의 소유권을 가져오지 않고, 단지 그 데이터를 참조만 합니다.&[T] 또는 &mut [T] 형태로 불변 또는 가변 참조로 표현됩니다.현재 아이템에 대한 참조자(Rectangle)를 하나의 인수로 받아서, 순서를 매길 수 있는 K 타입의 값을 반환합니다. #[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let mut list = [
Rectangle { width: 10, height: 1 },
Rectangle { width: 3, height: 5 },
Rectangle { width: 7, height: 12 },
];
list.sort_by_key(|r| r.width);
println!("{:#?}", list);
}
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let mut list = [
Rectangle { width: 10, height: 1 },
Rectangle { width: 3, height: 5 },
Rectangle { width: 7, height: 12 },
];
let mut sort_operations = vec![];
let value = String::from("by key called");
list.sort_by_key(|r| {
sort_operations.push(value);
r.width
});
println!("{:#?}", list);
}

let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
v1_iter)는 표준 라이브러리에 정의된 Iterator라는 이름의 트레이트를 구현

let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
for val in v1_iter {
println!("Got: {}", val);
}
into_iter를 호출 iter_mut을 호출sum 메서드가 있는데, 반복자의 소유권을 가져온 다음 반복적으로 next를 호출하는 방식으로 순회하며, 따라서 반복자를 소비 #[test]
fn iterator_sum() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let total: i32 = v1_iter.sum();
assert_eq!(total, 6);
}
반복자 어댑터 메서드인 map을 호출하는 예를 보여주는데, 클로저를 인수로 받아서 각 아이템에 대해 호출하여 아이템 전체를 순회합니다. v1.iter().map(|x| x + 1)) 를 만듭니다:v1.iter().map(|x| x + 1))를 소비하기 위해서 collect 메서드를 사용할 것인데, let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
assert_eq!(v2, vec![2, 3, 4]);
자신의 환경을 캡처하는 클로저
impl Config {
pub fn build(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("not enough arguments");
}
let query = args[1].clone();
let file_path = args[2].clone();
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config {
query,
file_path,
ignore_case,
})
}
}
args[1]) 대신 반복자의 소유권을 갖도록 build 함수를 변경할 수 있습니다. fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::build(&args).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});
// --생략--
}
fn main() {
let config = Config::build(env::args()).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});
// --생략--
}

impl Config {
pub fn build(
mut args: impl Iterator<Item = String>,
) -> Result<Config, &'static str> {
args.next();
let query = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a query string"),
};
let file_path = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a file path"),
};
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config {
query,
file_path,
ignore_case,
})
}
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new();
for line in contents.lines() {
if line.contains(query) {
results.push(line);
}
}
results
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.contains(query))
.collect()
}
반복자 스타일을 선호합니다. 고수준의 추상화지만, 컴파일되면 대략 직접 작성한 저수준의 코드와 같은 코드 수준으로 내려갑니다.fn sum_array(arr: &[i32]) -> i32 {
let mut sum = 0;
for i in 0..arr.len() {
sum += arr[i];
}
sum
}
fn main() {
let array = [1, 2, 3, 4, 5, 6, 7, 8];
println!("Sum: {}", sum_array(&array));
}
이 코드는 배열의 요소를 순차적으로 더하는 단순한 루프입니다. for 반복문은 arr의 길이만큼 실행되며, 각 반복마다 배열의 요소를 더하게 됩니다.
fn sum_array(arr: &[i32]) -> i32 {
let mut sum = 0;
let len = arr.len();
let mut i = 0;
// 루프 언롤링을 적용한 부분
while i + 3 < len {
sum += arr[i] + arr[i + 1] + arr[i + 2] + arr[i + 3];
i += 4;
}
// 남은 요소를 처리하는 루프
while i < len {
sum += arr[i];
i += 1;
}
sum
}
while 루프는 한 번에 4개의 요소를 더하게 됩니다.