학습
Zig 함수형 프로그래밍 패턴
Zig 함수형 프로그래밍 패턴 — 중급
Zig의 함수형 프로그래밍 패턴
1. 도입 (왜 배워야 하는가)
함수형 프로그래밍은 코드를 더 간결하고, 이해하기 쉽게 만들어 주며, 유지보수를 용이하게 해줍니다. 특히 Zig와 같은 저수준 언어에서 함수형 프로그래밍 패턴을 활용하면 메모리 관리와 성능 최적화를 손쉽게 할 수 있습니다. 함수형 프로그래밍을 모른다면 코드의 재사용성이 떨어지고, 복잡한 로직을 관리하기 힘들어질 수 있습니다. 결과적으로 버그가 생길 확률이 높아지고, 코드의 가독성이 낮아집니다.
2. 핵심 개념 설명
2.1. 고차 함수 (Higher-Order Functions)
고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수를 의미합니다. 실생활 비유로는 "요리사"를 생각해 볼 수 있습니다. 요리사는 다양한 재료(함수)를 사용해 음식을 만들 수 있으며, 특정 요리법(함수)으로 음식을 조리합니다.
| 용어 | 설명 |
|---|---|
| 고차 함수 | 함수를 인자로 받거나 반환하는 함수 |
| 콜백 함수 | 고차 함수에 의해 호출되는 함수 |
2.2. 불변성 (Immutability)
불변성은 한 번 생성된 데이터가 변경되지 않는 특성을 의미합니다. 마치 "한 번 정한 약속은 지켜야 한다"는 원칙과 비슷합니다. 데이터가 변경되지 않으면 예측 가능성이 높아지고, 코드의 안정성이 증가합니다.
3. 기본 코드 예제
다음은 Zig에서 고차 함수를 정의하고 사용하는 예제입니다.
fn applyFunction(fn: fn(i32) i32, value: i32) i32 {
return fn(value);
}
fn double(x: i32) i32 {
return x * 2;
}
pub fn main() void {
const result = applyFunction(double, 5);
std.debug.print("결과: {}\n", .{result});
}
실행 결과
결과: 10
코드 한 줄씩 동작 설명
applyFunction함수는 함수를 인자로 받습니다. 이 함수는 내부에서 인자로 받은 함수를 호출하여 결과를 반환합니다.double함수는 입력값을 두 배로 만드는 함수입니다.main함수에서applyFunction을 호출하면서double과5를 인자로 전달합니다.applyFunction은double(5)를 호출하고, 결과인10을 반환하여 출력합니다.- 문제: 함수의 반환 타입이 일치하지 않음.
- 해결: 반환 타입을 일치시킴.
- 문제: 데이터의 불변성을 위반함.
- 해결: 새로운 배열을 생성하여 데이터를 수정.
- 고차 함수는 코드의 재사용성을 높여줍니다.
- 불변성을 유지하면 코드의 안정성이 증가합니다.
- Zig에서의 함수형 프로그래밍은 성능 최적화에 유리합니다.
4. 실전 활용 예제
4.1. 쇼핑몰에서 장바구니를 구현할 때
장바구니에 담긴 상품의 가격을 합산하는 함수를 고차 함수로 구현할 수 있습니다.
const std = @import("std");
fn sumPrices(prices: []const i32) i32 {
var totalPrice: i32 = 0;
for (prices) |price| {
totalPrice += price;
}
return totalPrice;
}
pub fn main() void {
const itemsPrices = [_]i32{10000, 3500, 1500};
const total = sumPrices(itemsPrices);
std.debug.print("총 가격: {}\n", .{total});
}
실행 결과
총 가격: 15000
4.2. 데이터 필터링
데이터 목록에서 특정 조건을 만족하는 항목만 필터링하는 고차 함수를 사용할 수 있습니다.
fn filter(data: []const i32, predicate: fn(i32) bool) []i32 {
var filtered: []i32 = &[_]i32{};
for (data) |item| {
if (predicate(item)) {
filtered = filtered ++ [_]{item};
}
}
return filtered;
}
fn isEven(num: i32) bool {
return num % 2 == 0;
}
pub fn main() void {
const numbers = [_]i32{1, 2, 3, 4, 5, 6};
const evens = filter(numbers, isEven);
std.debug.print("짝수: {}\n", .{evens});
}
실행 결과
짝수: [2, 4, 6]
5. 흔한 실수와 주의사항
5.1. 잘못된 함수 시그니처
// 잘못된 예제
fn applyFunction(fn: fn(i32) f32, value: i32) i32 { / ... / }
5.2. 불변성을 무시하기
var items = [_]i32{1, 2, 3};
items[0] = 5; // 불변성을 위반
6. 정리
다음에 학습하면 좋은 주제는 Zig의 메모리 관리와 병렬 프로그래밍입니다. 이 두 주제는 Zig의 강력한 기능을 더욱 활용할 수 있게 해줍니다.