Dart 심화 문법(3) - 함수(Function)와 제네릭(Generics)
Today I Learned (250701) 2-2.
함수
- 특정 작업을 수행하는 코드 블록
- 입력을 받아서 특정 작업을 수행하고, 그 작업에 대한 결과를 반환하는 코드 블록
함수의 구성
1. 반환 타입
- 함수가 반환하는 값의 데이터 타입
- 함수가 값을 반환하지 않는 경우에는 void로 선언
2. 함수 이름
- 함수의 이름
- 함수를 실행시킬(호출할) 때 사용
3. 매개변수
- 함수 내부로 전달되어 코드 블록에서 사용하는 값
- 1개 이상 가질 수 있고, 개수에 제한이 없음
4. 실행할 코드
- 함수가 호출되면 실행되는 코드 블록
5. 반환값
- 함수의 코드 블록이 실행된 후 반환되는 값
- 결과값이라고 생각
[반환타입] [함수이름] ([매개변수 타입] [매개변수 이름]) {return [반환값];}
void printName() {
print('화춘기');
} //함수이름: printName
bool isOddNumber(int number) {
return number % 2 != 0;
}
/* 반환타입: bool / 함수이름: isOddNumber
매개변수 타입: int / 매개변수 이름: number
반환값: number % 2 ! = 0
bool isNull(int? number) {
return number == null;
}
/* 반환타입: bool / 함수이름: isNull
매개변수 타입: int? / 매개변수 이름: number
반환값: number == null
int add(int a, int b) {
return a + b;
}
/* 반환타입: int / 함수이름: add
매개변수 타입: int, int / 매개변수 이름: a, b
반환값: a + b
[함수이름]([매개변수 이름]) {return [반환값];}
- 타입 추론이 가능하기 때문에 반환 타입과 매개변수 타입을 생략해도 되지만,
Dart 공식 문서에는 추천하지 않는다고 되어 있음
printName() {
print('화춘기');
} //함수이름: printName
isOddNumber(number) {
return number % 2 != 0;
}
/* 함수이름: isOddNumber
매개변수이름: number
반환값: number % 2 ! = 0
add(a, b) {
return a + b;
}
/* 함수이름: add / 매개변수 이름: a, b
반환값: a+b
[반환타입] [함수 이름]([매개변수 타입] [매개변수 이름]) => 반환값;
- 반환값이 하나의 표현식으로 나타낼 수 있는 경우만 사용 가능
bool isOddNumber(int number) => number % 2 != 0;
/* 반환타입: bool / 함수 이름: isOddNumber
매개변수 타입: int / 매개변수 이름: number
반환값: number % 2 ! = 0
int multiply(int a, int b) => a * b;
/* 반환타입: int / 함수이름: multiply
매개변수 타입: int, int / 매개변수 이름: a, b / 반환값: a * b
실행: 함수 이름을 가지고 호출
void printName() {
print('화춘기');
}
printName(); // 화춘기
bool isOddNumber(int number) {
return number % 2 != 0;
}
bool isTwoOddNumber = isOddNumber(2);
print(isTwoOddNumber); // false
int add(int a, int b) {
return a + b;
}
int sum = add(2, 4);
print(sum); // 6
void main() {...}
main()
- 모든 프로그램은 실행을 시작하기 위한 함수(최상위 함수)를 반드시 가져야 하는데 Dart에서는 main() 함수가 그 역할을 함
- main()함수의 코드 블록 안에 코드를 넣어야 그 코드가 실행됨
ㄴ main() 함수의 코드 블록 안에 코드를 넣지 않으면 코드는 실행되지 않음
ㄴ 코드를 실행했는데 아무런 결과가 나오지 않는다면 main() 함수의 코드 블록에 코드를 잘 넣었는지 확인
- 반환값이 없기 때문에 반환 타입이 void로 설정됨
void main() {
print('안녕하세요 !'); // 안녕하세요 !
}
- List<String> 타입인 매개변수를 가질 수도 있음
void main(List<String> arguments) {
print(arguments);
}
/* 이 매개변수를 반드시 사용할 필요는 없음
Flutter 애플리케이션을 개발할 때는 사용하지 않고,
Command Line (터미널, 명령 프롬프트)을 실행할 때 주로 사용
👉 함수는 특정 작업을 수행하는 코드를 하나의 함수로 만들고,
그 작업을 수행해야 하는 곳마다 그 함수를 호출하도록 하면
같은 코드를 여러 번 쓰지 않아도 돼서 효율적인 코드를 짤 수 있음
void main() {
int one = 1;
int two = 2;
print(one + two); // 3
int three = 3;
int four = 4;
print(three + four); // 7
int five = 5;
int six = 6;
print(five + six); // 11
int seven = 7;
int eight = 8;
print(seven + eight); // 15
} //같은 동작을 하는 코드를
void printSum(int a, int b) {
print(a + b);
}
void main() {
printSum(1, 2); // 3
printSum(3, 4); // 7
printSum(5, 6); // 11
} //함수로 만들어서 사용하면 효율적인 코드를 짤 수 있음
제네릭(Generics)
- 클래스나 함수에서 데이터 타입을 일반화하여 다양한 타입을 지원할 수 있게 하는 기능
- 제네릭 종류: 제네릭 클래스 / 제네릭 함수
[타입 파라미터] [함수 이름]<타입 파라미터>([매개변수]) {...}
T getFirstElement<T>(List<T> list) {
return list[0];
}
/* 타입 파라미터는 보통 영어 대문자 한글자 (ex. E, T, S, K, V) 로 표현
실제 코드를 실행할 때 타입 파라미터 자리에 실제 데이터 타입을 넣으면 됨
- List<int>, List<String>, Set<int>, Set<String> 등등..
List, Set, Map은 각각 List<E>, Set<E>, Map<E, E> 형태로 정의되어 있고,
타입 파라미터인 E에 여러 타입이 올 수 있음
- 특정 타입에 의존하지 않고, 여러 타입에 대해 동일한 코드를 적용할 수 있어서 재사용성 높은 코드를 짤 수 있음
int getFirstNumber(List<int> numbers) {
return numbers[0];
}
String getFirstWord(List<String> words) {
return words[0];
}
void main() {
var numbers = [0, 1, 2, 3];
print(getFirstNumber(numbers)); // 0
var words = ['a', 'b', 'c'];
print(getFirstWord(words)); // a
} //같은 동작을 하는 코드를
T getFirstElement<T>(List<T> list) {
return list[0];
}
void main() {
var numbers = [0, 1, 2, 3];
print(getFirstElement(numbers)); // 0
var words = ['a', 'b', 'c'];
print(getFirstElement(words)); // a
} //제네릭 함수로 만들어서 사용하면 효율적임