Dart에서 함수와 메소드의 매개변수 전달 방식은 다양한 형태로 지원되며, 각 방식에 따라 함수의 동작 방식이 달라진다. 이 섹션에서는 Dart에서 제공하는 매개변수 전달 방식과 그 활용법을 자세히 살펴보자.

1. 기본 매개변수 전달

기본 매개변수 전달 방식은 함수를 정의할 때 매개변수를 함수의 인자로 지정하여 전달하는 방식이다. 함수가 호출될 때 인자 값이 순서대로 전달된다. Dart에서는 기본적으로 값에 의한 전달(pass by value) 방식이 사용된다. 이는 전달된 값의 복사본이 함수로 전달된다는 것을 의미한다.

예제:

void increment(int number) {
  number++;
}

void main() {
  int value = 10;
  increment(value);
  print(value); // 출력 결과는 여전히 10
}

위 코드에서 increment 함수는 number 값을 증가시키지만, main 함수에서 선언된 value에는 영향이 없다. 이는 값에 의한 전달로 인해 함수 내에서 변경된 값이 호출된 함수 외부에 반영되지 않기 때문이다.

2. 선택적 매개변수

Dart는 함수의 매개변수를 선택적으로 정의할 수 있는 방법을 제공한다. 선택적 매개변수는 크게 두 가지로 나뉜다: 위치 선택적 매개변수이름 선택적 매개변수이다.

위치 선택적 매개변수 (Positional Optional Parameters)

위치 선택적 매개변수는 대괄호([])를 사용하여 선언한다. 이 매개변수들은 선택적으로 전달할 수 있으며, 전달되지 않을 경우 null 값 또는 기본값이 사용된다.

예제:

void greet(String name, [String? message]) {
  print('Hello, $name!${message ?? ''}');
}

void main() {
  greet('Alice'); // Hello, Alice!
  greet('Bob', 'Good to see you!'); // Hello, Bob! Good to see you!
}

위 코드에서 greet 함수는 두 번째 매개변수인 message를 선택적으로 받을 수 있으며, 전달되지 않을 경우 null로 처리된다. ?? 연산자를 사용하여 null일 때 빈 문자열을 출력하게 설정하였다.

이름 선택적 매개변수 (Named Optional Parameters)

이름 선택적 매개변수는 중괄호({})를 사용하여 선언하며, 함수 호출 시 매개변수 이름을 명시하여 값을 전달한다. 이 방식은 매개변수의 순서에 상관없이 호출할 수 있어 더욱 유연하게 사용할 수 있다.

예제:

void greet({required String name, String? message}) {
  print('Hello, $name!${message ?? ''}');
}

void main() {
  greet(name: 'Alice'); // Hello, Alice!
  greet(name: 'Bob', message: 'Good to see you!'); // Hello, Bob! Good to see you!
}

이름 선택적 매개변수에서 required 키워드를 사용하여 반드시 값을 전달해야 하는 매개변수를 지정할 수 있다. 위 코드에서 name 매개변수는 필수이지만, message는 선택적이다.

3. 기본값 지정

매개변수에 기본값을 지정할 수 있는 기능도 Dart에서 제공하는 매우 유용한 특징 중 하나이다. 기본값은 선택적 매개변수에서 사용되며, 함수가 호출될 때 해당 매개변수에 값이 전달되지 않으면 기본값이 사용된다.

예제:

void greet(String name, {String message = 'How are you?'}) {
  print('Hello, $name!$message');
}

void main() {
  greet('Alice'); // Hello, Alice! How are you?
  greet('Bob', message: 'Good to see you!'); // Hello, Bob! Good to see you!
}

위 코드에서 message 매개변수는 기본값으로 'How are you?'를 갖는다. 따라서 함수가 호출될 때 message 매개변수를 전달하지 않으면 기본값이 사용된다.

4. 값에 의한 전달 (Pass by Value)

Dart에서 매개변수는 값에 의한 전달 방식으로 처리된다. 이는 함수로 전달된 인자의 복사본이 함수 내에서 사용된다는 의미이다. 전달된 인자의 값이 함수 내부에서 변경되더라도, 함수 외부의 값에는 영향을 미치지 않는다.

예제:

void updateValue(int value) {
  value = 20;
}

void main() {
  int x = 10;
  updateValue(x);
  print(x); // 출력: 10
}

이 경우 x 값이 함수 내에서 변경되더라도, 함수 외부에서는 여전히 10의 값을 유지하게 된다. 이는 값을 복사하여 함수에 전달하기 때문에 발생하는 현상이다.

5. 참조에 의한 전달을 흉내내기 (Mimicking Pass by Reference)

Dart는 기본적으로 값에 의한 전달을 사용하지만, 참조 타입(예: 객체나 리스트)을 이용하여 참조에 의한 전달(pass by reference)를 흉내낼 수 있다. 참조 타입은 객체의 주소값을 전달하므로, 함수 내부에서 객체를 수정하면 외부에도 영향을 미치게 된다.

예제:

void updateList(List<int> numbers) {
  numbers[0] = 100;
}

void main() {
  List<int> myList = [1, 2, 3];
  updateList(myList);
  print(myList); // 출력: [100, 2, 3]
}

이 예제에서 리스트 myList는 참조 타입이므로 함수에서 리스트의 첫 번째 값을 변경하면, 함수 외부에서도 그 변경 사항이 반영된다. 이는 참조를 전달하는 방식이기 때문에 발생하는 현상이다.

6. 매개변수로 함수 전달

Dart에서는 함수를 매개변수로 전달할 수 있다. 이를 통해 고차 함수(higher-order function)를 작성할 수 있으며, 함수 내에서 다른 함수를 호출하거나 처리할 수 있게 된다.

예제:

void executeFunction(Function func, String value) {
  func(value);
}

void printMessage(String message) {
  print(message);
}

void main() {
  executeFunction(printMessage, 'Hello, Dart!'); // 출력: Hello, Dart!
}

위 코드에서 executeFunction 함수는 함수와 문자열을 인자로 받아 해당 함수를 호출한다. 이처럼 함수를 매개변수로 전달함으로써 유연한 코드 작성을 할 수 있다.

7. 콜백 함수 사용

콜백 함수는 특정 작업이 완료된 후 호출되는 함수이다. Dart에서는 비동기 작업이나 이벤트 처리 중에 콜백 함수를 자주 사용한다.

예제:

void fetchData(Function callback) {
  // 데이터 처리 후 콜백 함수 호출
  callback('Data fetched successfully!');
}

void main() {
  fetchData((message) {
    print(message); // 출력: Data fetched successfully!
  });
}

위 코드에서 fetchData 함수는 콜백 함수를 인자로 받아 비동기적으로 데이터 처리 후 해당 콜백을 호출한다. 콜백 함수는 주로 비동기 프로그래밍에서 중요한 역할을 한다.