Elixir Reference
Elixir 프로그래밍 레퍼런스
Elixir Reference 소개
Elixir Reference는 Elixir 언어의 핵심 기능을 6개 카테고리로 정리한 검색 가능한 치트 시트입니다. 기본 문법에는 불변 재바인딩 의미론을 가진 변수 바인딩, 경량 심볼 상수인 아톰(:ok, :error, true), "#{}" 문자열 보간, head/tail 구조 분해를 지원하는 리스트/튜플의 차이, %{}와 구조적 업데이트 구문을 사용하는 맵 리터럴, 조건식(if/else, 다중 절을 위한 cond, 값 매칭을 위한 case), def(공개)와 defp(비공개)를 사용한 함수 정의, map/filter/reduce 같은 함수형 목록 연산을 위한 Enum 모듈이 포함됩니다. 모든 항목은 실제적인 예제와 함께 관용적인 Elixir 코드를 보여줍니다.
패턴 매칭 카테고리는 Elixir의 가장 독특한 기능 중 하나를 강조합니다. = 연산자는 대입 연산자가 아닌 매칭 연산자입니다. 오른쪽 값을 왼쪽 패턴과 매칭하여 변수를 바인딩합니다. 이는 튜플({:ok, result} = {:ok, 42}), 리스트([head | tail] = [1,2,3]), 맵(%{name: name} = user)에 모두 적용됩니다. case 표현식은 중첩된 구조체 패턴을 포함한 여러 절에서 패턴 매칭을 사용합니다. 함수 절 패턴 매칭은 깔끔한 다중 절 함수 정의(factorial/0과 factorial/n)를 가능하게 합니다. 핀 연산자(^)는 재바인딩을 방지하고 매칭에서 값 동등성을 강제합니다. with 특수 폼은 실패할 수 있는 다단계 작업에 이상적인 깔끔한 else 핸들러와 함께 여러 매칭 작업을 연결합니다. 프로세스 카테고리는 Elixir의 액터 모델 동시성을 다룹니다. 격리된 프로세스 생성을 위한 spawn, receive 블록에서 패턴 매칭을 사용한 메시지 전달을 위한 send/receive, 병렬 작업을 위한 Task.async/await, 간단한 키-값 상태 래퍼인 Agent, 충돌 감지와 내결함성을 위한 spawn_link와 Process.monitor가 포함됩니다.
GenServer 카테고리는 상태 있는 서버 프로세스를 위한 OTP 핵심 구성 요소를 보여줍니다. use GenServer로 GenServer 정의, 초기 상태를 위한 init/1 구현, 동기 요청-응답을 위한 handle_call/3({:reply, value, new_state}으로 응답), 비동기 메시지를 위한 handle_cast/2({:noreply, new_state} 반환), 임의 메시지(Process.send_after의 타이머 틱 포함)를 위한 handle_info/2, Supervisor.start_link와 one_for_one 전략으로 슈퍼비전 트리 시작이 포함됩니다. 파이프와 지연 평가 카테고리는 왼쪽에서 오른쪽으로 변환을 구성하기 위한 |> 파이프 연산자, 익명 함수 단축 표기를 위한 & 캡처 연산자, 대용량 데이터셋에서 중간 리스트를 구체화하지 않고 지연 열거를 위한 Stream을 다룹니다. 매크로 카테고리는 컴파일 타임 메타프로그래밍을 설명합니다. AST를 변환하는 매크로를 정의하는 defmacro, 코드 인용과 보간을 위한 quote/unquote, 모듈 __using__ 훅을 호출하는 use, 컴파일 타임 상수와 문서화를 위한 @모듈 속성이 포함됩니다.
주요 기능
- 기본 문법: 변수 바인딩, atom, 문자열 보간, 리스트/튜플, 맵 업데이트 구문, if/cond/case, def/defp, Enum.map/filter/reduce
- 패턴 매칭: = 매칭 연산자, 튜플/리스트/맵 구조 분해, case 패턴, 함수 절 매칭, 핀 연산자(^)
- 통합 오류 처리와 함께 다단계 패턴 매칭 연결을 위한 with 특수 폼
- 동시성: spawn, send/receive 메시지 전달, Task.async/await, Agent 상태 관리, spawn_link/monitor
- GenServer: start_link, init, handle_call(동기), handle_cast(비동기), handle_info, 재시작 전략을 가진 Supervisor
- 왼쪽에서 오른쪽 함수 구성을 위한 |> 파이프 연산자와 익명 함수 단축 표기를 위한 & 캡처 연산자
- 중간 리스트 구체화 없이 대용량 컬렉션 처리를 위한 지연 평가 Stream 모듈
- 매크로: AST 조작을 위한 defmacro, quote/unquote, use 훅, 컴파일 타임 메타데이터를 위한 @모듈 속성
자주 묻는 질문
Elixir에서 =를 사용한 패턴 매칭은 어떻게 동작하나요?
Elixir에서 =는 대입 연산자가 아닌 매칭 연산자입니다. 런타임은 오른쪽 값을 왼쪽 패턴과 매칭하려 시도하며, 패턴에서 바인딩되지 않은 변수를 바인딩합니다. 예를 들어 {status, value} = {:ok, 42}는 status를 :ok에, value를 42에 바인딩합니다. 매칭이 실패하면(예: {:error, reason} = {:ok, 42}) MatchError가 발생합니다. 함수 인수, case 절, with 표현식 어디서나 적용됩니다.
핀 연산자(^)란 무엇이고 언제 사용하나요?
핀 연산자 ^는 패턴 매칭 중 변수가 재바인딩되는 것을 방지하고 대신 현재 값에 대한 동등성 검사를 강제합니다. ^ 없이는 매칭에서 x = 2가 x를 조용히 재바인딩합니다. ^x = 2를 사용하면 Elixir는 x가 이미 2와 동일한지 확인하고 그렇지 않으면 MatchError를 발생시킵니다. 새로운 값을 캡처하는 것이 아니라 기존 변수 값과 매칭하려 할 때 case 절이나 receive 블록에서 사용하세요.
GenServer에서 handle_call과 handle_cast의 차이는 무엇인가요?
handle_call/3은 GenServer.call/2로 전송된 동기 메시지를 처리합니다. 호출자는 서버가 {:reply, 응답, 새_상태}로 응답할 때까지 블록됩니다. handle_cast/2는 GenServer.cast/2로 전송된 비동기 메시지를 처리합니다. 호출자는 즉시 반환(fire-and-forget)되고 서버는 응답 없이 {:noreply, 새_상태}를 반환합니다. 반환 값이 필요한 쿼리에는 call을, 확인이 필요 없는 명령에는 cast를 사용하세요.
with 표현식이란 무엇이고 언제 사용해야 하나요?
with 표현식은 여러 <- 패턴 매칭을 순차적으로 연결합니다. 모든 매칭이 성공하면 do 블록이 실행됩니다. 매칭이 실패하면 else 블록이 매칭되지 않은 값을 처리합니다. 이것은 각 단계가 {:ok, value} 또는 {:error, reason}을 반환할 수 있는 다단계 작업에서 깊게 중첩된 case 표현식을 대체하는 관용적인 Elixir 패턴입니다. 진행하기 전에 두 개 이상의 작업이 모두 성공해야 할 때 with를 사용하세요.
Enum과 Stream의 차이는 무엇인가요?
Enum 함수는 즉시 평가(eager)됩니다. 전체 컬렉션을 즉시 처리하고 새 목록을 반환합니다. Stream 함수는 지연 평가(lazy)됩니다. Enum.to_list, Enum.take 등으로 소비될 때만 실행되는 구성 가능한 변환 파이프라인을 만듭니다. 대용량 컬렉션이나 무한 범위(1..1_000_000)의 경우 Stream은 중간 리스트를 크게 만드는 것을 방지합니다. 소-중형 컬렉션에는 Enum을, 대용량 데이터셋 처리나 많은 변환 단계 구성 시에는 Stream을 사용하세요.
Elixir 프로세스는 OS 스레드와 어떻게 다른가요?
Elixir 프로세스(BEAM VM을 통해)는 매우 경량입니다. 수백만 개를 spawn할 수 있습니다. 각 프로세스는 독립적인 힙(공유 메모리 없음)을 가지고, 메시지 전달을 통해서만 통신하며, BEAM 스케줄러에 의해 OS 스레드 전반에 걸쳐 협력적으로 스케줄링됩니다. 프로세스 격리는 한 프로세스의 충돌이 연결되지 않은 다른 프로세스에 영향을 미치지 않음을 의미합니다. 이 모델은 충돌한 프로세스가 자동으로 재시작되는 내결함성 슈퍼비전 트리를 가능하게 합니다.
모듈 안에서 use GenServer는 어떤 역할을 하나요?
use GenServer는 컴파일 타임에 GenServer.__using__/1 매크로를 호출하여 모든 GenServer 콜백(init, handle_call, handle_cast, handle_info, terminate, code_change)의 기본 구현을 모듈에 주입합니다. 그런 다음 필요한 콜백만 재정의하면 됩니다. 이것은 Elixir의 매크로 기반 믹스인 패턴입니다. use는 대상 모듈에서 __using__을 트리거하며, 라이브러리 작성자가 정의한 모든 코드를 주입할 수 있습니다.
파이프 연산자 |>는 어떻게 동작하나요?
파이프 연산자 |>는 왼쪽 표현식의 결과를 오른쪽 함수의 첫 번째 인수로 전달합니다. 이를 통해 중첩된 함수 호출 없이 위에서 아래로 읽기 쉬운 구성 스타일이 가능합니다. "Hello World" |> String.downcase() |> String.split()은 String.split(String.downcase("Hello World"))와 동일합니다. 파이프 연산자는 순수한 문법적 설탕으로 런타임 오버헤드가 없습니다.