안녕하세요! 이번 포스팅에서는 Flutter 개발에 필수적인 Dart 문법 중 클로저, 고차함수, 익명함수에 대해서 알아보겠습니다.
그전에 무조건 앞에 문법 확인하고 오세요 ~
1. Dart 언어의 기본 문법 1편 - 변수, 함수, 클래스, 리스트, 조건문, 반복문
2. Dart 언어의 기본 문법 2편 - Map, Null Safety, Enum, Set, 연산자
3. Dart 언어의 기본 문법 3편 - Future와 async/await
1. 클로저(Closure)란?
클로저는 외부 함수의 변수에 접근할 수 있는 내부 함수입니다.
Dart에서는 함수가 생성된 스코프(scope)에 정의된 변수에 접근할 수 있는 특성을 클로저라고 합니다.
1-1 클로저의 특징
- 외부 함수의 지역 변수에 접근 가능: 내부 함수는 외부 함수가 실행된 이후에도 외부 함수의 변수에 접근할 수 있습니다.
- 상태를 유지: 외부 변수의 상태를 기억하고 변경할 수 있습니다.
- 클로저는 상태를 유지해야 하는 비즈니스 로직에서 유용합니다.
Function makeCounter() {
int count = 0;
return () {
count++;
return count;
};
}
void main() {
var counter = makeCounter();
print(counter()); // 출력: 1
print(counter()); // 출력: 2
print(counter()); // 출력: 3
}
설명
- makeCounter함수는 count라는 변수를 생성하고, 이 변수에 접근하는 익명 함수를 반환 합니다.
- 반환된 익명 함수는 클로저로 동작하며, count의 상태를 유지합니다.
2. 익명 함수(Anonymous Function)란?
익명 함수는 이름이 없는 함수입니다.
한 번만 사용하거나 간단한 로직을 처리할 때 사용합니다.
기본 문법
(parameters) {
// 함수 내용
};
익명 함수는 변수에 할당하거나 다른 함수의 인수로 전달할 수 있습니다.
익명 함수 사용 예제
void main() {
// 익명 함수를 변수에 할당
var multiply = (int a, int b) {
return a * b;
};
print(multiply(3, 4)); // 출력: 12
// 함수 내에서 직접 사용
var list = [1, 2, 3];
list.forEach((item) {
print(item * 2); // 2, 4, 6 출력
});
}
3. 고차 함수(Higher-Order Function)란?
고차 함수는 다른 함수를 인자로 받거나, 함수를 반환하거나, 또는 둘 다 할 수 있는 함수 입니다.
Dart는 함수를 1급 객체로 다루기 때문에, 함수를 변수처럼 전달하거나 반환할 수 있습니다.
3-1 고차 함수의 특징
- 함수를 인수로 전달: 함수가 다른 함수에 인수로 전달됩니다.
- 함수를 반환: 함수가 다른 함수를 반환합니다.
예제 1: 함수를 인수로 전달
void printWithExclamation(String message, Function modify) {
print(modify(message));
}
void main() {
printWithExclamation('Hello', (msg) => '$msg!');
// 출력: Hello!
}
예제 2: 함수를 반환
Function makeMultiplier(int multiplier) {
return (int value) => value * multiplier; // 함수 반환
}
void main() {
var doubleIt = makeMultiplier(2);
print(doubleIt(5)); // 출력: 10
var tripleIt = makeMultiplier(3);
print(tripleIt(5)); // 출력: 15
}
4. 고차 함수, 익명함수, 클로저 사용 예제
4-1 익명 함수와 고차 함수의 조합
익명 함수는 고차 함수와 함께 자주 사용됩니다.
Dart에서 제공하는 컬렉션 메서드(forEach, map, where, reduce 등)에서 특히 유용합니다.
예제: 익명 함수와 고차 함수의 조합
void main() {
var numbers = [1, 2, 3, 4, 5];
// map: 각 요소에 함수를 적용
var squaredNumbers = numbers.map((num) => num * num);
print(squaredNumbers.toList()); // 출력: [1, 4, 9, 16, 25]
// where: 조건에 맞는 요소만 필터링
var evenNumbers = numbers.where((num) => num % 2 == 0);
print(evenNumbers.toList()); // 출력: [2, 4]
// reduce: 모든 요소를 하나로 결합
var sum = numbers.reduce((a, b) => a + b);
print(sum); // 출력: 15
}
4-2 고차 함수의 실용적 활용
예제: 정렬 함수 전달
void main() {
var names = ['Charlie', 'Alice', 'Bob'];
// 고차 함수로 정렬 기준 제공
names.sort((a, b) => a.compareTo(b));
print(names); // 출력: [Alice, Bob, Charlie]
}
예제: 커스텀 조건 필터링
List<int> filterNumbers(List<int> numbers, bool Function(int) test) {
return numbers.where(test).toList();
}
void main() {
var numbers = [1, 2, 3, 4, 5, 6];
// 짝수 필터링
var evenNumbers = filterNumbers(numbers, (num) => num % 2 == 0);
print(evenNumbers); // 출력: [2, 4, 6]
// 홀수 필터링
var oddNumbers = filterNumbers(numbers, (num) => num % 2 != 0);
print(oddNumbers); // 출력: [1, 3, 5]
}
4-3 익명 함수 vs 람다식
람다식(화살표 함수)은 익명 함수의 간단한 형태입니다. 한 줄로 표현할 수 있는 함수에 적합합니다.
예제: 익명 함수와 람다식 비교
void main() {
// 일반 익명 함수
var multiply = (int a, int b) {
return a * b;
};
// 람다식 (화살표 함수)
var multiplyShort = (int a, int b) => a * b;
print(multiply(3, 4)); // 출력: 12
print(multiplyShort(3, 4)); // 출력: 12
}
4-4 익명 함수와 클로저의 조합
익명 함수는 클로저로 활용될 때 강력한 기능을 발휘합니다.
void main() {
var list = [1, 2, 3];
var multiplyBy = 2;
// 클로저를 사용하는 익명 함수
var multipliedList = list.map((item) => item * multiplyBy).toList();
print(multipliedList); // 출력: [2, 4, 6]
}
설명:
- 익명 함수 (item) => item * multiplyBy는 외부 스코프의 변수 multiplyBy를 참조합니다.
- 이는 클로저로 동작하여 multiplyBy의 값을 유지하고, 각 요소에 곱합니다.
4-5 고차 함수와 클로저의 조합
클로저는 고차 함수와 결합하여 함수의 동작을 동적으로 변경하거나 상태를 유지하는 데 유용합니다.
Function createAdder(int base) {
return (int value) => base + value; // 클로저 생성
}
void main() {
var addFive = createAdder(5);
var addTen = createAdder(10);
print(addFive(3)); // 출력: 8
print(addTen(3)); // 출력: 13
}
설명:
- createAdder는 매개변수 base를 기억하는 클로저를 반환합니다.
- 반환된 함수는 외부 변수 base에 접근하여 값을 유지하고, 이를 사용해 덧셈을 수행합니다.
4-5 고차 함수와 익명함수, 클로저의 차이점과 관계
특징 | 익명 함수 | 고차 함수 | 클로저 |
정의 | 이름이 없는 함수 | 다른 함수를 인자로 받거나 반환하는 함수 | 외부 함수의 변수를 참조하는 내부 함수 |
역할 | 간단한 로직 처리 | 재사용 가능한 유연한 함수 설계 | 상태 유지 및 외부 변수 참조 |
활용 | 고차 함수의 인자로 자주 사용 | 코드 재사용성과 확장성 증가 | 비즈니스 로직에서 상태 관리 |
결론
익명 함수, 고차 함수, 그리고 클로저는 각각의 역할을 가지지만, 서로 밀접하게 연결되어 있습니다.
- 익명 함수는 간단한 로직에서 유용하며, 클로저로 동작할 수도 있습니다.
- 고차 함수는 코드의 재사용성을 높이고, 클로저를 활용해 동적 동작을 구현할 수 있습니다.
- 클로저는 함수형 프로그래밍의 핵심으로, 상태를 유지하거나 외부 변수를 참조하는 데 적합합니다.
익명 함수와 고차 함수만 다룰 수도 있지만,
클로저를 포함하면 Dart의 함수형 프로그래밍의 강력한 가능성을 더 잘 전달할 수 있습니다.
클로저를 활용한 상태 관리와 같은 실용적인 예제를 포함해보세요! 😊
'Flutter > Dart' 카테고리의 다른 글
Dart 기본 문법 3 - Future와 async/await (0) | 2025.01.10 |
---|---|
Dart 기본 문법 2 - 맵(Map), Null Safety, Enum, Set, 연산자 (0) | 2025.01.10 |
Dart 기본 문법 1 - 변수, 함수, 클래스, 리스트, 조건문, 반복문 (0) | 2025.01.10 |