1편에서 이 코드를 보여준 적이 있다.
그리고 거기서 느낌표가 붙으면 매크로란 것도 설명하였다.
여기서 한 가지 들 수 있는 의문,
왜 println!은 매크로여야만 했는가?
그 이유는 다음과 같다.
println!은 위처럼 인자 수가 다양해질 수 있다.
그러나 러스트는 함수에선 가변 인자를 사용할 수 없게 되어 있다.
그것을 별로 좋지 않다고 판단했기 때문인 듯하다.
그래서 println!은 가변 인자를 사용할 수 있게 매크로 형태로 되어 있는 것이다.
함수와 매크로의 차이는 1편에서도 말했지만,
함수는 런타임 때 호출되고 매크로는 컴파일 타임 때 다른 코드로 변환되는 것이다.
println! 속 {} 이 중괄호는 다양한 형태로 사용될 수 있다
그러나 보통의 경우에는 그냥 {} 이 중괄호만으로도 충분하다
사용자가 입력한 내용을 새로운 줄이 아니라
같은 줄에 '입력하시오: ' 이런 형태로 써놓고 입력을 받고 싶을 수도 있다
그럴 땐 println!이 아니라 print!을 써야 한다.
다만 print!는 콘솔 버퍼에 입력만 할 뿐 콘솔창에 출력되게 만들지는 않는다
그래서 그 이후 println!을 쓰거나 따로 flush라는 것을 쓰든지 해야 한다
println!을 쓰면 출력은 되지만 줄은 바뀌기 때문에,
이때는 줄을 바꾸지 않는 flush만 쓰는 것이 맞을 것이다
여기서 unwrap이라는 것이 등장했는데,
이건 Option<T>또는 Result<T, E>를 벗기는 작업이다.
flush는 Result<()>를 반환한다.
( 1편에서도 말했지만 괄호는 유닛 타입을 의미한다. )
참고로 Result<T>는 다음과 같다.
type Result<T> = std::result::Result<T, std::io::Error>;
unwrap을 사용할 땐 Some(T)인 상태여야 하며,
None 상태일 경우 프로그램이 터지게 된다.
러스트에선 이를 panic이라고 한다
따라서 unwrap을 쓰는 것은
대충 다음과 같은 경우라고 볼 수 있다.
1. 어차피 연습용이라 대충 진행하고 싶은 경우
(터지면 그냥 다시하거나, 오류 처리를 나중에 한다는 마인드)
2. 그냥 터지게 만들어서 오류를 확인하고 싶은 경우
이땐 사실 expect란 것이 있는데,
이것도 터지긴 하는데 대신 본인이 정한 메시지를 출력하고 터지게 한다
3. 사실상 터질 일이 없는 경우
한마디로 '설마 터지겠어?'라는 마인드
이상적으로 봤을 땐 그다지 좋지 않다고 볼 수도 있겠지만,
결과적으로 안 터지기만 하면 상관없다고 생각하기는 한다
에러 핸들링을 하고 싶다면 다음과 같이 match를 써야 한다
( => 뒷부분의 내용은 쓰고 싶은 대로 쓰면 된다. 필요하다면 중괄호까지 사용 가능. )
이제 입력에 대해서 알아보도록 하겠다.
입력은 항상 String 형태로 받게 된다.
사용자가 뭐라뭐라 입력하고 엔터를 누르면 read_line을 통해 해당 내용이 들어가게 된다.
이때 주의해야 할 점은 read_line은 String의 내용을 덮어씌우지 않는다
항상 String에 추가만 하기 때문에,
새로 초기화하려면 입력을 받기 전 clear() 메소드를 호출해줘야 한다.
read_line도 Result를 리턴한다. 그런데 저기에는 물음표가 있는 것을 볼 수 있다.
물음표는 사실상 다음 코드와 동일하다.
이것도 함수의 마지막에 놓으면 알아서 그것이 리턴된다.
그런데 그 패턴이 너무 흔하기 때문에 물음표로 축약해 놓은 것이다.
Ok(_)라고 써놓은 이유는, Ok 내부의 내용은 어찌되든 좋다는 뜻이다.
왜냐하면 Ok(buffer)를 리턴하는 것 자체가 목표이기 때문이다.
하지만 이 부분이 마지막에 있지 않으면 함수에 이것이 리턴되지는 않는다.
(편의상 match에서 값이 튀어나온 것도 그냥 리턴이라 표현함)
즉, 마지막에 있거나 누군가 받고 있는 것도 아닌데 저렇게 쓰는 경우는
그냥 쓰긴 써야 하는데 코드를 줄여야 해서 그렇게 쓰는 것이다.
String으로 받은 값은 다음과 같이 정수로 변환할 수도 있다.
1. let my_int = my_string.parse::<i32>().unwrap(); // i32를 parse에 명시
2. let my_int: i32 = my_string.parse().unwrap(); // i32를 변수에 명시
편의상 이때 unwrap을 쓰긴 했지만
당연하게도 이 경우에는
유저가 숫자가 아니라 글자를 치는 것만으로도
간단하게 에러를 일으킬 수 있기 때문에
에러에 대한 처리를 꼭 해주는 것이 좋다.
간단하게 예를 들긴 했지만
이 경우엔 입력 과정과 parse 전체에 loop를 걸어
정상적인 결과를 받을 때까지 반복하거나 할 수 있을 것이다.
1편에서 3편까지 한 내용은 다음과 같다.
1. 기본적인 자료형
2. 컨트롤 플로우
3. 사용자 입출력
이제 이를 이용해서 간단한 프로그램을 만들어 볼 수 있다.
다음 4편에서는 간단한 가위바위보 게임과 숫자 추측 게임을 만들어보도록 하겠다.
해당 댓글은 삭제되었습니다.
아 다시 보니 글이 좀 깨져 있어서.. 수정 좀 하겠습니다
연봉3억 쌉고수 개발자 개추 ㄷㄷ