다트 문법공부 함수편
기본 타입과 제어문을 넘어 함수까지 왔다.
함수와 클래스, 고급 타입정도만 숙지해두면
바로 간단한 프로그램을 제작해볼 수 있을듯 하다.
함수
int addIntNumbers(int num1, int num2) {
return num1 ?? 0 + num2;
}
리턴타입을 함수명 앞으로 선언해주고,
파라미터를 타입과 함께 지정해준 뒤
자유롭게 활용하면 된다.
통칭 람다함수라 불리는 녀석으로,
그냥 함수를 좀 더 간단하게 표현할 것이다.
Function addIntNumbers = (int num1, int num2) => num1 + num2;
print(addIntNumbers(1, 2)); // 3
위처럼 () => {}의 간단한 형태로 표현 가능하다.
또, 위 표현처럼 함수를 object화 할 수 있는데,
함수의 선행타입을 Function으로 표기하고
변수처럼 활용하면 된다.
나중에 콜백함수를 활용해야 할 경우
자주 써야할 듯 하다.
한가지 예시만 적어보고 넘어가겠다.
void main() {
addNumbers(
1, 2,
(result) {
print("정답은 ${result}입니다.");
},
() {
print("정수가 아닌 값은 더할 수 없습니다.");
}
);
// 정답은 3입니다.
addNumbers(
1, 2.5,
(result) {
print("정답은 ${result}입니다.");
},
() {
print("정수가 아닌 값은 더할 수 없습니다.");
}
);
// 정수가 아닌 값은 더할 수 없습니다.
}
void addNumbers(
dynamic num1, dynamic num2,
Function (int result) onSuccess,
Function onFail
) {
if(num1.runtimeType != int || num2.runtimeType != int) {
onFail();
} else {
onSuccess(num1 + num2);
}
}
이렇게 callback 함수를 등록해
필요한 곳에 활용할 수 있다.
함수실행 시 파라미터 명을 지정해줘야
하는 것을 Named parameter,
지정해주지 않고 그냥 순서대로 받는 것을
Positional parameter라고 한다.
코틀린이나 파이썬에서는 함수를 실행할 때,
파라미터 명을 표기해주던 말던 큰 상관이 없었다.
즉, 다음과 같은 사용에 문제가 없다는 것이다.
// Kotlin
fun addNum(num1: Int, num2:Int): Int {
return num1 + num2
}
addNum(num1 = 1, num2 = 2) // 3
addNum(1, 2) // 3
// Python
def addNum(num1, num2):
return num1 + num2
addNum(1, 2) // 3
addNum(num1=1, num2=2) // 3
하지만 다트에서는 이렇게 하면 에러가난다.
// Dart
Function addIntNumbers = (int num1, int num2) => num1 + num2;
print(addIntNumbers(1, 2)); // 3
print(addIntNumbers(num1: 1, num2: 2)); // Uncaught TypeError
이는 함수 선언 당시에, positional parameter와
Named parameter를 구분해줘야 때문이다.
즉, 별다른 구분이 없다면 positional parameter
방식으로 실행하고, Named parameter 방식으로
쓰려면 별도의 방식이 필요하다는 것이다.
파라미터 사용이 엄격하다는 것은 swift와 닮았다.
다만 이름과 순서를 모두 지켜 사용하는 것을
디폴트로 두고있는 swift가 조금은 더 엄격해보인다.
서론이 길었다. Named parameter를 지정해보자.
void main() {
print(myFriends(first: "영수", second: "준식"));
print(myFriends(second: "준식", first: "영수"));
}
String myFriends({String? first, String? second}) {
return "첫 번째 친구: ${first ?? "없음"}, 두 번째 친구: ${second ?? "없음"}";
}
// 첫 번째 친구: 영수, 두 번째 친구: 준식
// 첫 번째 친구: 영수, 두 번째 친구: 준식
위처럼 {} 기호를 통해 지정한 파라미터는
사용시 파라미터 이름을 함께 표시해주어야한다.
이렇게 사용할 시 파라미터 순서에 관계없이
같은 결과가 출력됨을 확인할 수 있다.
여기서 눈썰미가 좋은 사람은
굳이 first와 second를 nullable로
선언한 것을 볼 수 있을 것이다.
이는 기본적으로 Named parameter는
optional한 값으로 간주하기 때문이다.
즉 안써도 그만인 것들만 넣을 수 있다.
void main() {
print(myFriends(first: "영수"));
print(myFriends(second: "준식"));
print(myFriends());
}
String myFriends({String? first, String? second}) {
return "첫 번째 친구: ${first ?? "없음"}, 두 번째 친구: ${second ?? "없음"}";
}
// 첫 번째 친구: 영수, 두 번째 친구: 없음
// 첫 번째 친구: 없음, 두 번째 친구: 준식
// 첫 번째 친구: 없음, 두 번째 친구: 없음
물론 이렇게 optional한 값을 활용할 때도
있겠지만, 함수에 반드시 필요한 parameter
이면서 이름을 표기해주고 싶은 경우도
있지 않을까?
그래서 required가 있다.
void main() {
print(addIntNumbers(num1: 1, num2: 2)); // 3
print(addIntNumbers(num2: 2, num1: 1)); // 3
print(addIntNumbers(num1: 1, num2: 2, num3: 4)); // 7
print(addIntNumbers(num1: 1, num3: 4, num2: 2)); // 7
print(addIntNumbers(num2: 2, num3: 4)); // error - 빨간줄
}
int addIntNumbers({required int num1, required int num2, int? num3}) {
return num1 + num2 + (num3 ?? 0);
}
이렇게 required를 지정해주면
변수명을 반드시 표기해줘야 하면서,
optional값이 아닌 필수 파라미터로
쓸 수 있다.
required를 지정해주지 않은 num3는 생략해도
실행되지만, num1이나 num2를 생략하면
아예 빨간줄로 실행 자체가 불가능하다.
여럿이 협업하는 환경에서는
웬만하면 required와 Named parameter를
써주는게 좋지 않을까 싶다.
함수 파라미터를 받아올 때 default값을
지정하는 방법 또한 positional이냐 named냐에
따라 다르다.
// positional parameter의 default값 지정
void main() {
print(addIntNumbers(1, 2, 0)); // 3
print(addIntNumbers(1, 2)); // 4
}
int addIntNumbers(int num1, int num2, [int num3=1]) {
return num1 + num2 + num3;
}
이렇게 []를 감싸주고 원하는
디폴트 값을 지정해주면 된다.
그냥 코틀린이나 파이썬처럼
addNumbers(int num1, int num2 = 2)
이런식으로 표기하면 어땠을까 싶지만
엄격한게 버그 줄이기에는 좋겠지..
이어서 Named 방식을 보자.
// named parameter의 default값 지정
void main() {
print(addIntNumbers(num1: 1, num2: 2, num3: 3)); // 6
print(addIntNumbers(num1: 1, num2: 2)); // 4
}
int addIntNumbers({required int num1, required int num2, int num3=1}) {
return num1 + num2 + num3;
}
원래 named parameter는 optional로 간주해
nullable한 값을 받아오는 것이 기본이었다.
하지만 위처럼 디폴트 값을 함께 써줄 경우
nullable이 아니어도 된다.
마무리
기본, 관습, 타입, 제어문, 함수까지
정리가 끝났다.
이제 class나 interface(다트에 있는지는 모르겠다),
abstract class나 그 외 고급 활용문법만
훑어보면 드디어 서비스를 만들어 볼 수 있다.
얼른 마무리 해야지!