쓰다보니 너무 길어져서 여러 편으로 나누었다. 계속 살펴보자.
Input:
3
1 2 3
4 5 6
7 8 9
우선 내 경우 위의 input을 input.txt 파일에 저장하고, 컴파일한 파일인 main에 리눅스 파이프( | )를 통해 입력을 전달했다.
코드에서 파일을 오픈해서 값을 읽어와도 되지만 아래 명령어가 훨씬 간단하다.
cat input.txt | ./main
코드를 살펴보면, read_line() 함수는 읽어 온 값의 바이트를 반환한다. if let Ok(0)과 read_line()이 반환한 값이 Ok(0)으로 매치된다면 EOF(End of File) 이므로 입력을 break한다.
아래 블럭으로 넘어가서, split_whitespace() 함수로 공백을 통해 문자열을 각각의 단어로 나눈다.
그리고 이터레이터에서 처음 n개의 요소를 건너뛰고 이후 요소를 반환하는 skip(n) 메서드가 연결된다. 여기선 예시 입력의 첫 번째 줄인 3을 건너뛴다 (어차피 각 줄의 크기가 3으로 고정되어 있고, 입력의 끝은 EOF로 판단하기 때문에 여기선 필요없는 값이다.)
.map() 메서드는 각각의 이터레이터 값을 매핑해준다. 더 자세한 설명은 여기로..
여기서 클로저가 등장하는데, 간단히 말해 “자신이 정의된 범위에서 변수를 포착해 사용하도록 해주는 기능”이다.
자신이 정의된 범위 라는 표현이 모호하다면 공식 문서를 참조하도록 하자.
현재 expresion의 맥락에서 각 요소가 <Vec>, i32형태로 변환될 것임이 드러나 있으므로 그냥 parse() 를 사용할 수 있다.
우선 공식 문서의 시그니처를 보도록 하자.
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err>
where
F: FromStr,
parse() 메서드는 Result 열거형의 값을 반환한다고 한다. 열거형은 struct의 field처럼 여러 값을 가질 수 있는데, 그 값을 variant라고 하며 열거형의 인스턴스는 여러 variants중 오직 한 가지 값만을 가질 수 있다. Result 열거형은 Prelude에 포함된, 러스트가 기본적으로 제공하는 열거형이다.
Result 열거형은 아래의 값을 반환하는데,
Ok(F) 또는 Err(<F as FromStr>::ERR)
쉽게 말해 에러가 없다면 F 타입의 값을 Ok variant에 담아 반환하고 에러가 있다면 FromStr trait가 구현된 F의 ERR를 Err variant에 담하서 반환한다는 말이다.
Ok(F)에서 F를 꺼내는 방법은 match, unwrap(), expect() 등 다양하다.
마지막으로 collection을 사용해 iterator의 값을 collection 타입으로 묶어준다. collect() 함수에 대한 설명은 아래에 있다.
.collect<Vec>()에 세미콜론이 붙지 않는 걸 볼 수 있는데, 이 블럭이 let v에 값을 전달하기 위한 expression이기 때문이다.
( Rust에서 statement(i.e. 선언문)는 값을 반환하지 않으며 ;로 끝난다, expression(i.e. 표현식)은 값을 반환하며 ;를 붙이지 않는다.
함수에서 값을 반환할 때 return으로 반환값을 명시하거나 코드 마지막 줄에 expression으로 값을 반환할 수도 있다. )
지금까지의 코드는 첫 번째 n을 무시하고 이후의 모든 입력을 공백으로 분할해 1차원 벡터에 담았다.
그럼 어떻게 1차원 벡터의 값들을 3개씩 끊어서 사용할까?
chunks() 메서드를 사용하면 된다.
- An iterator over a slice in (non-overlapping) chunks (chunk_size elements at a time), starting at the beginning of the slice.
- When the slice len is not evenly divided by the chunk size, the last slice of the iteration will be the remainder.
This struct is created by the chunks method on slices.
chunks() 메서드는 주로 배열이나 벡터 등 시퀀스 타입에 사용되며,
슬라이스를 지정된 크기의 청크로 나누어 이터레이터를 반환한다.
슬라이스가 매개변수로 넘긴 청크 크기로 나눠지지 않는다면, 마지막 청크는 나머지 크기의 슬라이스가 된다.
더 빠르고 효율적인 / 다양한 입출력에 대해선 다음에 더 알아보도록 하자.