"123" 은 숫자 123 이 아니다
나이를 입력받아 한 살을 더해 보겠습니다.
Console.Write("나이: ");
string age = Console.ReadLine(); // 20 을 입력했습니다
Console.WriteLine(age + 1); // 201
21 이 아니라 201 입니다. 오타도 버그도 아니고, 코드가 시킨 대로 한 것입니다.
"123" 안에 들어 있는 것
앞에서 글자마다 번호가 붙어 있다고 했습니다. 문자 '1' 의 번호는 49 입니다.
'0' 이 48이니 그다음입니다.
그러니까 문자열 "123" 이 메모리에 들고 있는 것은 이렇습니다.
앞에서 이렇게 정리했습니다. 메모리에는 비트만 있고, 그걸 무엇으로 읽을지는 타입이 정한다.
"123" 과 123 은 같은 것을 다르게 읽는 것도 아니고, 아예 다른 비트가 들어 있는 것입니다.
+ 는 양쪽을 보고 할 일을 정한다
앞에서 연산자를 다룰 때 + 가 두 가지 일을 한다고 했습니다.
어느 쪽인지는 양옆에 무엇이 있느냐로 정해집니다.
Console.WriteLine(1 + 2); // 3 양쪽이 숫자면 덧셈
Console.WriteLine("1" + "2"); // 12 양쪽이 문자열이면 이어붙이기
Console.WriteLine("20" + 1); // 201 한쪽이 문자열이면 이어붙이기
세 번째가 처음 예제의 정체입니다. 한쪽이 문자열이면 다른 쪽도 문자열로 바꿔서 이어붙입니다.
1 이 "1" 이 되고, "20" 뒤에 붙어 "201" 이 됩니다.
에러가 안 나기 때문에 더 골치입니다. 앞에서 본 좁은 칸으로 가는 변환은 컴파일러가 막아 세우기라도 하는데, 이건 조용히 되고 결과만 이상합니다.
입력은 언제나 문자열이다
Console.ReadLine() 은 무엇을 입력하든 string 을 돌려줍니다.
숫자를 입력했다고 숫자가 되지 않습니다. 파일에서 읽거나 통신으로 받은 것도 마찬가지입니다.
계산하려면 바꿔야 합니다. 바꾸려는 타입 이름 뒤에 Parse 를 붙입니다.
int n = int.Parse("123");
double d = double.Parse("3.14");
bool flag = bool.Parse("true");
Parse 는 못 바꾸면 터진다
문제는 바꿀 수 없는 값이 들어왔을 때입니다.
int.Parse("abc"); // FormatException
int.Parse(""); // FormatException
int.Parse("3.5"); // FormatException int 자리에 소수점
int.Parse("99999999999"); // OverflowException int 범위를 넘음
마지막 것은 앞에서 본 정수의 범위와 이어집니다. int 가 담을 수 있는 범위 밖이라
조용히 한 바퀴 도는 게 아니라 예외로 알려줍니다. 캐스팅과 다른 점입니다.
(int) 는 잘라내고 넘어가지만 Parse 는 멈춥니다.
예외가 나면 프로그램이 그 자리에서 죽습니다. 코드를 짠 사람 입장에서는 확실해서 좋지만, 사용자가 오타 한 번 냈다고 프로그램이 종료되면 안 됩니다.
TryParse 는 알려주기만 한다
같은 일을 하되 실패했을 때 행동이 다릅니다. 터지는 대신 false 를 돌려줍니다.
out int n 이 낯설 텐데, “결과를 담을 변수를 여기 줄 테니 채워 달라” 는 뜻입니다.
TryParse 가 돌려주는 값은 성공했는지 여부(bool)라서, 바꾼 숫자를 받을 자리가 따로 필요합니다.
out 이 정확히 어떻게 동작하는지는 메서드를 다룰 때 봅니다.
주의할 게 하나 있습니다. 실패하면 n 에 0 이 들어갑니다.
그래서 n == 0 으로 실패를 판단하면 안 됩니다. 사용자가 진짜 0 을 입력한 경우와 같아집니다.
판단은 항상 돌려받은 bool 로 합니다.
될 때까지 다시 묻기
TryParse 가 진가를 발휘하는 자리는 앞에서 본 반복문과 만날 때입니다.
int n;
while (!int.TryParse(Console.ReadLine(), out n))
{
Console.WriteLine("숫자만 입력해주세요.");
}
Console.WriteLine($"{n} 의 두 배는 {n * 2}");
바꾸는 데 실패하는 동안 계속 다시 묻습니다. 성공하면 조건이 false 가 되어 빠져나오고,
그 시점에 n 에는 제대로 된 숫자가 들어 있습니다.
Parse 로는 이렇게 못 씁니다. 첫 오타에서 이미 프로그램이 없습니다.
정리하면 기준은 이렇습니다.
바깥에서 들어온 값은
TryParse, 코드 안에서 만든 확실한 값은Parse.
사용자 입력, 파일, 통신으로 받은 것은 전부 바깥에서 온 값입니다.
반대 방향은 그냥 된다
숫자를 문자열로 바꾸는 것은 실패할 일이 없어서 TryToString 같은 게 없습니다.
int n = 1234567;
string a = n.ToString(); // "1234567"
string b = $"{n}"; // "1234567" 앞에서 본 보간
string c = n.ToString("N0"); // "1,234,567" 형식 지정자도 그대로 쓸 수 있습니다
앞에서 본 형식 지정자를 ToString 에 그대로 넘길 수 있습니다.
보간의 콜론 뒤에 적던 것과 같은 문자열입니다.
정리
- 입력으로 받은 것은 언제나 문자열이다. 숫자를 입력해도 숫자가 되지 않는다.
"123"은 문자 세 개의 번호를 담고 있고,123은 2진수 하나를 담고 있다. 다른 비트다.+는 한쪽이 문자열이면 이어붙인다."20" + 1은"201"이다.- 바꾸려는 타입 이름 뒤에
Parse를 붙인다.int.Parse,double.Parse. Parse는 못 바꾸면 예외를 던진다. 범위를 넘겨도 예외다. 캐스팅처럼 잘라내지 않는다.TryParse는 터지는 대신false를 돌려주고, 결과는out변수에 담아 준다.- 실패하면
out변수에0이 들어간다. 성공 여부는 반드시 돌려받은bool로 판단한다. - 바깥에서 들어온 값은
TryParse, 코드 안에서 만든 확실한 값은Parse.