[Dart] 1. 함수
※ https://dart-ko.dev/language/functions#the-main-function 을 참고하여 작성하였습니다.
기본 함수 구현
return 타입 명시: bool
1 2 3
bool isNoble(int atomicNumber){ return _nobleGases[atomicNumber] != null; }
return 타입 명시 X: bool이 없어도 작동됨, 하지만 타입 명시를 권장
1 2 3
isNoble(atomicNumber){ return _nobleGases[atomicNumber] != null; }
하나의 표현식 만을 가지는 함수: ⇒ 를 사용
1
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
매개변수
named 매개변수
[형식] {매개변수1, 매개변수2, …}
defualt 값이 없으면
→ void enableFlags({bool? bold, bool? hidden}) 처럼 자료형을 nullable(?) 로 지정해야 함
→ 함수 호출: enableFlags(bold: true, hidden: false);
default 값이 있으면
→ void enableFlags({bool bold= false, bool hidden= false}) { … }
→ 함수 호출: enableFlags(bold: true);
optional positional 매개변수
[형식] [매개변수1, 매개변수 2, …]
역시, default 값이 없으면 자료형을 nullable(?)로 선언해야 함
default 값이 있으면,
→ default 값은 반드시!! 컴파일 타임 상수로 지정되어야 함
required positional 매개변수
main() 함수
Explanation
- 최상위 함수
- void 반환
optional List
의 매개변수를 가짐 1 2 3
void main(List<String> arguments){ print(arguments); }
일급 객체로서의 함수
- 함수의 인자에 함수(printElement)를 넘기는 것이 가능
1 2 3 4 5 6 7
void printElement(int element){ print(element); } var list= [1, 2, 3]; list.forEach(printElement);
- 변수에 함수의 할당이 가능 → 익명 함수
- msg: 함수의 인수
1 2
var loudify= (msg)=> '!!!{msg.toUpperCase()}!!!'; assert(loudify('hello') == '!!!HELLO!!!');
익명 함수
Explanation
이름이 없는 함수
이름이 없는 함수: 익명 함수, 람다, 클로져
위의 loudify의 변수처럼,
익명 함수를 변수에 선언해서 컬렉션에 추가/제거 하는 것도 가능!
예제 1) 전체 과정
1 2 3 4 5 6 7 8
void main(){ const list= ['apples', 'bananas', 'oranges']; list.map((item) { return item.toUpperCase(); }).forEach((item) { print('$item: ${item.length}'); }); }
예제 2) => 사용
1 2 3 4 5
void main(){ const list= ['apples', 'bananas', 'oranges']; list .map((item) => item.toUpperCase()) .forEach((item) => print('$item: ${item.length}'));
렉시컬 스코프(lexically scoped)
Explanation
변수가 선언된 위치에 따라 그 변수를 사용할 수 있는 범위가 정해지며,
내부 함수는 외부 함수의 변수에 접근할 수 있음
변수의 범위를 확인하고 싶다면→ 중괄호의 끝을 따라가기
예시> 최상위 수준까지 모든 수준의 변수 사용이 가능
렉시컬 클로저
클로저: 함수와 함수가 정의된 환경을 묶는 것
- 일반 함수의 클로저: 함수가 정의된 스코프의 변수를 기억하는 함수 객체
- 인스턴스 메서드의 클로저: 인스턴스와 함께 묶인 메서드
클로저 함수
- 클로저 함수 자신이 정의된 스코프를 기억함
- 클로저는 함수가 생성될 때의 변수를 기억하고 접근할 수 있음
예제
1 2 3 4 5 6 7 8 9 10 11
Function makeAdder(int addBy) { return (int i) => addBy + i; } void main() { var add2 = makeAdder(2); // (int i) => 2+i 를 가진 add2(클로저) var add4 = makeAdder(4); // (int i) => 4+i 를 가진 add4(클로저) assert(add2(3) == 5); // 3를 add2의 인자로 받아 참 assert(add4(3) == 7); // 3을 add4의 인자로 받아 참 }
assert()는 조건식이 참이면 아무것도 출력되지 않고,
거짓일 경우 예외를 발생시킴
동등성 테스트 함수
- assert(함수1 == 함수2)
- 함수: 최상위 함수, 정적 함수, 인스턴스 함수의 동등성 확인
반환 값
반환 값이 명시되어 있지 않은 경우: 암묵적으로 return null; 을 명시
1 2
foo() {} assert(foo() == null);
두 개 이상의 값을 반환
1 2 3
(String, int) foo(){ return ('something', 42); }
제너레이터 함수
Explanation
- 데이터의 시퀀스를 지연하여(lazily) 생성하고 싶을 때 제너레이터 함수 사용
동기식 제너레이터
- Iterable 객체 반환
- 함수의 바디: sync*
- 함수의 호출: for
1 2 3 4
Iterable<int> naturalsTo(int n) sync* { int k = 0; while (k < n) yield k++; }
비동기식 제너레이터: Stream 객체 반환
- Stream 객체 반환
- 함수의 바디: async*
- 호출: awiat for
1 2 3 4
Stream<int> asynchronousNaturalsTo(int n) async* { int k = 0; while (k < n) yield k++; }
재귀를 이용한 제너레이터
1 2 3 4 5 6
Iterable<int> naturalsDownFrom(int n) sync* { if (n > 0) { yield n; yield* naturalsDownFrom(n - 1); } }