기본 타입
기본 타입
이번 장에서는 Elixir의 기본 타입을 하나씩 살펴볼게요. 정수(integer), 부동소수점(floating-point), 불리언(boolean), 원자(atom), 문자열(string)이 그 주인공이에요. 리스트나 튜플 같은 다른 데이터 타입은 다음 장에서 다룰 테니, 지금은 지면을 아껴두고요. 먼저 우리가 앞으로 만날 타입들을 눈으로 익혀볼까요.
출처: Elixir 공식 가이드
본문
이번 장에서는 Elixir의 기본 타입인 정수, 부동소수점, 불리언, 원자, 문자열을 배워볼게요. 리스트와 튜플 같은 다른 데이터 타입은 다음 장에서 다룰 거예요.
iex> 1 # 정수(integer)
iex> 0x1F # 정수(integer)
iex> 1.0 # 부동소수점(float)
iex> true # 불리언(boolean)
iex> :atom # 원자(atom / symbol)
iex> "elixir" # 문자열(string)
iex> [1, 2, 3] # 리스트(list)
iex> {1, 2, 3} # 튜플(tuple)
기본 산술 연산 (Basic arithmetic)
iex를 열고 다음 표현식들을 입력해 보세요.
iex> 1 + 2
3
iex> 5 * 5
25
iex> 10 / 2
5.0
10 / 2가 정수 5가 아니라 5.0이라는 부동소수점을 돌려준 게 보이죠. 이건 버그가 아니라 의도된 동작이에요. Elixir에서 / 연산자는 항상 부동소수점을 반환해요. 정수 나눗셈이나 나머지를 원한다면 div와 rem 함수를 쓰면 돼요.
iex> div(10, 2)
5
iex> div 10, 2
5
iex> rem 10, 3
1
여기서 흥미로운 점이 하나 있어요. 인자를 하나 이상 받는 함수를 호출할 때 괄호를 생략할 수 있거든요. 이 기능 덕분에 선언이나 제어 흐름을 쓸 때 훨씬 깔끔해져요. 다만 Elixir 개발자들은 보통 괄호를 쓰는 편을 선호해요.
이진수, 팔진수, 십육진수를 입력하는 축약 표기법도 지원돼요.
iex> 0b1010
10
iex> 0o777
511
iex> 0x1F
31
부동소수점은 소수점 뒤에 숫자가 최소 하나 있어야 하고, 과학적 표기법을 위한 e도 지원해요. Elixir의 부동소수점은 64비트 정밀도를 가져요.
iex> 1.0
1.0
iex> 1.0e-10
1.0e-10
round 함수를 쓰면 주어진 부동소수점에 가장 가까운 정수를 얻을 수 있고, trunc 함수를 쓰면 소수 부분을 버린 정수 부분만 얻을 수 있어요.
iex> round(3.58)
4
iex> trunc(3.58)
3
마지막으로, 다양한 데이터 타입을 다루다 보면 어떤 값이 특정 타입인지 확인하고 싶을 때가 생겨요. Elixir는 이를 위한 여러 판별(predicate) 함수를 제공해요. 예를 들어 is_integer로 어떤 값이 정수인지 아닌지 확인할 수 있어요.
iex> is_integer(1)
true
iex> is_integer(2.0)
false
is_float는 부동소수점인지, is_number는 정수 또는 부동소수점인지 확인할 수 있어요.
불리언과 nil (Booleans and nil)
Elixir는 true와 false를 불리언으로 지원해요.
iex> true
true
iex> true == false
false
Elixir에는 or, and, not라는 세 개의 불리언 연산자도 있어요. 이 연산자들은 엄격(strict) 한데, 첫 번째 인자로 불리언(true 또는 false)으로 평가되는 값을 기대한다는 뜻이에요.
iex> true and true
true
iex> false or is_boolean(true)
true
불리언이 아닌 값을 넘기면 예외가 발생해요.
iex> 1 and true
** (BadBooleanError) expected a boolean on left-side of "and", got: 1
or와 and는 단축 평가(short-circuit) 연산자예요. 왼쪽 값만으로 결과가 결정되면 오른쪽을 실행하지 않아요.
iex> false and raise("This error will never be raised")
false
iex> true or raise("This error will never be raised")
true
Elixir는 값이 없음을 나타내는 nil과, nil까지 다루는 논리 연산자들(||/2, &&/2, !/1)도 제공해요. 이 연산자들에서는 false와 nil이 "거짓 같은(falsy)" 값이고, 그 외에는 모두 "참 같은(truthy)" 값으로 취급돼요.
# or
iex> 1 || true
1
iex> false || 11
11
# and
iex> nil && 13
nil
iex> true && 17
17
# not
iex> !true
false
iex> !1
false
iex> !nil
true
마찬가지로, 다른 언어에서 "거짓 같은" 값으로 취급되곤 하는 0이나 "" 같은 값도 Elixir에서는 "참 같은" 값이에요.
실용적인 규칙 하나를 알려드릴게요. 불리언을 기대하는 상황이라면 and, or, not을 쓰고, 인자 중 하나라도 불리언이 아닐 수 있다면 &&, ||, !을 쓰는 거예요.
원자 (Atoms)
원자는 값이 곧 자기 자신의 이름인 상수예요. 어떤 언어에서는 심볼(symbol)이라고 부르기도 하죠. 서로 다른 값들을 나열할 때 유용해요.
iex> :apple
:apple
iex> :orange
:orange
iex> :watermelon
:watermelon
원자는 이름이 같으면 서로 같아요.
iex> :apple == :apple
true
iex> :apple == :orange
false
흔히 연산의 성공·실패 상태를 표현할 때 :ok, :error 같은 값을 써요. 그리고 아까 봤듯이 true와 false도 사실은 원자예요.
iex> true == :true
true
iex> is_atom(false)
true
iex> is_boolean(:false)
true
Elixir는 false, true, nil 이 세 개의 원자에 대해서만 맨 앞의 :를 생략할 수 있게 해줘요.
문자열 (Strings)
Elixir의 문자열은 쌍따옴표로 감싸고, UTF-8로 인코딩돼요.
iex> "hellö"
"hellö"
참고: Windows를 쓰고 있다면 터미널이 기본적으로 UTF-8을 사용하지 않을 수 있어요. IEx에 들어가기 전에
chcp 65001을 실행하면 현재 세션의 인코딩을 바꿀 수 있어요.
<> 연산자로 두 문자열을 연결할 수 있어요.
iex> "hello " <> "world!"
"hello world!"
문자열 보간(interpolation)도 지원해요.
iex> string = "world"
iex> "hello #{string}!"
"hello world!"
문자열 연결은 양쪽이 모두 문자열이어야 하지만, 보간은 문자열로 변환될 수 있는 어떤 데이터 타입이든 지원해요.
iex> number = 42
iex> "i am #{number} years old!"
"i am 42 years old!"
문자열에는 줄바꿈도 들어갈 수 있어요. 이스케이프 시퀀스로 표현할 수 있죠.
iex> "hello
...> world"
"hello\nworld"
iex> "hello\nworld"
"hello\nworld"
IO 모듈의 IO.puts 함수로 문자열을 출력할 수 있어요.
iex> IO.puts("hello\nworld")
hello
world
:ok
IO.puts가 출력한 뒤 :ok라는 원자를 반환한다는 점도 눈여겨보세요.
Elixir의 문자열은 내부적으로 바이너리(binary)라고 불리는 연속된 바이트들의 나열로 표현돼요.
iex> is_binary("hellö")
true
문자열의 바이트 수도 구할 수 있어요.
iex> byte_size("hellö")
6
"hellö"는 그래핌(grapheme, 시각적으로 구분되는 문자 단위)이 5개인데 바이트 수는 6이에요. ö라는 그래핌이 UTF-8에서 2바이트를 차지하기 때문이죠. 그래핌 수 기준의 실제 길이는 String.length로 얻을 수 있어요.
iex> String.length("hellö")
5
String 모듈에는 유니코드 표준에 따라 동작하는 함수들이 많이 있어요.
iex> String.upcase("hellö")
"HELLÖ"
구조 비교 (Structural comparison)
Elixir도 ==, !=, <=, >=, <, > 같은 비교 연산자를 제공해요. 숫자들을 비교할 수 있죠.
iex> 1 == 1
true
iex> 1 != 2
true
iex> 1 < 2
true
원자, 문자열, 불리언 등도 비교할 수 있어요.
iex> "foo" == "foo"
true
iex> "foo" == "bar"
false
값이 같다면 정수와 부동소수점도 같은 것으로 비교돼요.
iex> 1 == 1.0
true
iex> 1 == 2.0
false
하지만 정수와 부동소수점을 구분하고 싶다면 엄격 비교 연산자인 ===와 !==를 쓸 수 있어요.
iex> 1 === 1.0
false
Elixir의 비교 연산자는 어떤 데이터 타입 간에도 비교가 가능해요. 이 연산자들이 수행하는 비교를 구조 비교(structural comparison) 라고 불러요. 더 자세한 내용은 구조 비교와 의미 비교 문서에서 확인할 수 있어요.
Elixir에는 컬렉션을 표현하는 데이터 타입도 있는데, 바로 다음 장에서 배울 리스트와 튜플이에요. 프로세스를 통한 동시성과 내결함성을 다룰 때는 포트(port), pid, 참조(reference)도 이야기하게 될 텐데, 그것들은 좀 더 뒤의 장에서 만나기로 하고, 그럼 계속 나아가 볼게요.
더 알아보기
- 리스트와 튜플 (다음 장)