춘기IT/춘기개발

Dart 심화 문법(3) - 함수(Function)와 제네릭(Generics)

화춘기 2025. 7. 1. 14:42

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
} //제네릭 함수로 만들어서 사용하면 효율적임