지난 번 글에서 '가위 바위 보' 게임을 만들면서 컴퓨터가 '가위 바위 보' 중 어느 하나를 임의로 선택하도록 만들기 위해 rand 메서드를 사용해 봤다.
오늘은 rand 메서드의 또 다른 활용 예로 인증번호 생성기를 만들어 보려고 한다.
우리가 특정 사이트나 앱 등에 최초 가입을 하거나 상품이나 서비스를 구매하고 결제를 하려고 할 때 또는 아이디나 비밀번호가 생각이 나지 않을 때 등 본인이 맞는 지 확인을 하기 위해 인증 절차를 거치는 데, 이중 하나가 본인 명의의 휴대폰으로 6자리(꼭 6자리는 아니다)로 된 임의의 숫자를 보내서 사용자가 화면에 그 숫자를 입력하도록 하여 시스템에서 보내준 숫자와 맞는지 확인하는 방법이 있다.
간단하게 아래처럼 6자리 임의의 숫자를 만들 수 있다.
?> def gen_auth_num
?> num = ""
?> for i in 0..5
?> num += rand(10).to_s
?> end
?> return num
>> end
=> :gen_auth_num
>>
>> gen_auth_num
=> "666734"
>> gen_auth_num
=> "455014"
>> gen_auth_num
=> "988372"
rand(10) 은 정수 0에서 9까지 중 임의의 정수 하나를 돌려준다. 그 값을 차례대로 붙여 놓을 곳이 필요하므로 빈 문자열("")을 초기 값으로 갖는 변수 num 을 하나 만들었다.
지난번에 STDIN.gets 을 사용하여 키보드로 입력한 값이 숫자여도 프로그램에서는 문자열로 결과를 돌려받기 때문에 그 값을 숫자(정수)로 사용하기 위해서는 키보드 입력 값을 담고 있는 변수 input 에 대해 to_i 메서드를 호출(input.to_i)했었듯이, 이번에는 반대로 rand 메서드의 결과 값을 문자열로 변환하기 위해 to_s 메서드를 호출해 줘야 한다.
그래야 num 변수가 담고 있는 문자열 값에 rand 메서드가 반환한 값을 이어 붙일 수가 있다.
>> "a" + 2
(irb):1:in `+': no implicit conversion of Integer into String (TypeError)
"a" + 2
^
from (irb):1:in `<main>'
from <internal:kernel>:187:in `loop'
from C:/Ruby33-x64/lib/ruby/gems/3.3.0/gems/irb-1.13.1/exe/irb:9:in `<top (required)>'
from C:/Ruby33-x64/bin/irb:33:in `load'
from C:/Ruby33-x64/bin/irb:33:in `<main>'
앞의 코드 실행 결과를 보면 문자열("a")에 정수(2)를 더하려고 하니 에러를 내뱉는 걸 볼 수 있다. (TypeError)
프로그래밍을 잘하기 위해 여러 에러를 많이 접해보는 것도 중요하다. 한 번에 어떠한 에러나 버그도 없이 완벽하게 프로그램을 짤 수 있는 사람은 없고 결국 프로그래밍 과정 중에 에러나 버그를 만나고 수정해가는 과정이 필요하다.
따라서, 다양한 종류의 에러들을 미리 많이 접해보면 나중에는 실수가 줄어들고 에러를 수정하는 데 걸리는 시간도 단축시킬 수 있게 된다.
문자열에 다른 문자열을 이어 붙이기위해 += 을 사용했는데, 실제 그러한 역할을 하는 더 나은 메서드가 따로 있다.
바로 concat ('concatenate' 을 뜻함) 이다. += 과 concat 메서드를 사용하는 것의 차이는 아래 코드 실행 결과를 보면 알 수 있다.
>> str = "a"
=> "a"
>> str.object_id
=> 260
>> str += "b"
=> "ab"
>> str.object_id
=> 280
>> str.concat("c")
=> "abc"
>> str.object_id
=> 280
>>
뭐가 다른지 눈치 챘는가? += 을 사용할 때는 object_id 값이 달라졌지만 concat 메서드를 사용할 때는 object_id 값이 달라지지 않았다. 프로그램에서 '변수' 는 어떠한 값을 저장하기 위한 메모리 상의 특정 공간에 대한 이름이라고 생각하면 되고, 또 메모리 공간은 실제 각 공간마다 서로 다른 주소 값을 가지고 있는데, obejct_id 가 돌려주는 값이 바로 그 주소 값이라고 생각하면 된다. 우리는 '변수' 라는 이름을 사용해서 편하게 메모리에 원하는 값을 넣고 뺄 수 있는 것이다.
이와 유사한 예로 웹브라우저를 통해 구글이나 네이버 같은 인터넷 웹사이트를 들어갈 때 우리는 브라우저 주소창에 원하는 웹사이트의 주소를 'google.com' 또는 'naver.com' 처럼 입력하곤 하는데, 실제로 해당 웹사이트의 서버 주소는 '142.251.222.206' 처럼 숫자로 구성되어 있다. DNS 라는 고마운 서비스 중간에서 우리의 어려움을 덜어 주고 있는 것이다.
여러분이 cmd 창 'nslookup google.com' 명령을 실행할 때는 위에서 보이는 것과 다른 주소 값이 나올 수도 있다. 어쨌든 나는 웹브라우저 주소창에 'google.com' 대신 '142.251.222.206' 을 입력해도 구글 사이트가 잘 보이는 것을 확인했다.
다시 돌아와서, object_id 값이 바뀌는 게 뭐가 어떻다는 걸까? 솔직히 이번 프로그램처럼 이어 붙이는 문자열의 길이가 짧을 때는 별 상관이 없다. 오히려 += 가 코드가 더 짧고 간결해 보인다. 그러나 이어 붙이려는 문자열의 길이가 길고 이어 붙이는 횟수가 많을 수록 += 을 사용한 코드 보다는 concat 메서드를 사용하는 게 더 좋은 선택이다.
object_id 값이 바뀐다는 것은 프로그램 코드 상에서는 여전히 동일한 이름의 변수를 사용하지만 실제로는 새로운 메모리 공간을 다시 확보하는 일과 새로 확보한 공간에 지금까지의 값을 다시 쓰는 일이 필요하다.
아직은 기초적인 내용을 다뤄야 하는 글인데 어쩌다 보니 좀 깊이 들어와 버렸다. 지금은 그냥 그런가 보다하고 넘어가자.
See you again~~