#3.0 Defining a Function
void는 이 함수가 아무것도 return 하지 않고 콘솔에 출력하기만 한다는 뜻을 가진다.
String sayHello(String name){
return("Hello $name nice to meet you");
}
void main() {
}
만약 출력대신 return을 한다면 오류가 나는데, void는 return을 하지 않는 함수이기 때문에 그런 것이며,
이 경우 void를 return을 받고 있는 String으로 업데이트 해주면 된다.
sayHello는 String을 return 하는 함수 / 하나의 parameter을 가지며 이름은 $name.
꼭 void main 안에 있을 필요는 없다.
String sayHello(String name){
return("Hello $name nice to meet you");
}
void main() {
print(sayHello('dart'));
}
main안에 sayHello를 호출해주어야 한다.

곧바로 return하는 function을 가질 때 fat arrow syntax를 이용하여 코드를 변경 할 수 있다.
String sayHello(String name) => "Hello $name nice to meet you";
void main() {
print(sayHello('dart'));
}
fat arrow syntax는 코드가 한줄일 경우에 유용하게 사용 가능하다. (긴 경우에는 중괄호를 사용하고 마지막 코드를 return하는 형식으로)
num plus(num a, num b) => a + b;
예를 들어 a와 b를 더하는 함수를 선언했을때 위와 같이 사용 가능하다.
#3.1 Named Parameter
dart의 함수는 named parameter 라는 것을 지원한다. (플러터에서 자주 사용된다)
String sayHello(String name, int age, String country) {
return "Hello $name, you are $age, and you come from $country";
}
void main() {
print(sayHello('dart', 19, 'cuba'));
}
예를 들어 위와 같이 name, age, country 3가지 값을 출력하는 함수를 만들었을 때
해당 함수를 실행하기 위해 print(sayHello('dart', '19', 'cuba')); 는 작성자가 헷갈리기 쉽기 때문에 named argument를 사용하면 훨씬 나아진다.
String sayHello({String name, int age, String country}) {
return "Hello $name, you are $age, and you come from $country";
}
void main() {
print(sayHello(
age: 12,
country: 'cuba',
name: 'dart'
));
}
사용방법은 위와 같다. 먼저 함수 선언 쪽에서 중괄호를 추가하고, 아래에서는 해당 변수에 대한 값을 하나씩 정해준다.
하지만 이 경우에도 오류가 나는 것을 확인 할 수 있다. 그 이유는 numm saftey가 적용되어 있기 때문인데, 위처럼 3가지 값에 모두 값이 지정되지 않는 경우를 dart는 고려하고 있기 때문이다.
void main() {
print(sayHello(
age: 12,
));
}
예를 들어 유저가 나이만 입력하는 경우 등을 고려하고 있는 것이다. 이 문제를 해결하는 2가지 방법이 있다.
named argument에 default value를 정한다.
String sayHello({
String name = 'anon',
int age = 99,
String country = 'wakanda',
}) {
return "Hello $name, you are $age, and you come from $country";
}
void main() {
print(sayHello(
age: 12,
));
}
코드를 이렇게 작성하면 값을 모두 입력하지 않아도 문제 없이 출력된다.
하지만 default value 없이 유저에게 실제 data를 받아야 한다면 어떻게 해야 할까?
required 이용
String sayHello({
required String name,
required int age,
required String country,
}) {
return "Hello $name, you are $age, and you come from $country";
}
void main() {
print(sayHello(
age: 12,
country: 'cuba',
name: 'dart'
));
}
named parameter가 사실 required라고 명시해준다. 이런식으로 required를 이용하면, sayHello가 호출될 때 반드시 name, age, country 값이 필요하다는 것을 게 된다.
required modifier을 이용하여 필수 값으로 만들어주는 것이다.
#3.2 Recap
positional parameter
parameter의 순서가 String, String, int 일때 이 순서대로 값을 입력해주어야 하기 때문에 번거롭다.
sayHello("name", "country", "age") 이런식으로 각각의 위치에 어떤 값이 있는지 기억해야 한다.
선언되어 있는 함수와 호출되는 값 모두 확인해야 하기 때문에 2번씩 확인해야 한다.
named parameter
named parameter은 그럴 필요 없이 이름과 함께 입력해주기 때문에 번거롭지 않다.
print(sayHello(
age: 12,
country: 'cuba',
name: 'dart'
));
위처럼 parameter와 값을 함께 입력하여 한쪽만 봐도 알 수 있도록 한다.
required
유저가 값을 넣지 않는 경우를 방지하기 위하여 required를 이용할 수 있다.
defalut value
값이 없는 것을 대비하여 미리 값을 입력하는 default value를 이용할 수 있다.
#3.3 Optional Positional Parameters
만약 named argument를 적용하고 싶지 않은데 country는 required 하지 않게 하려면 어떻게 해야 할까?
String sayHello(
String name,
int age,
[String? country = 'cuba']
) =>
'Hello $name, you are $age years old from $country';
void main() {
sayHello('dart', 12);
}
대괄호를 씌워주고 country는 not required 라고 표시한다. default value를 부여한다.
이렇게 코드를 작성하면 마지막 argument를 보내지 않아도 sayHello 함수를 부를 수 있게 되었다.
#3.4 QQ Operator
이름을 대문자로 return 하는 함수 만들기
String capitalizeName(String? name) => name.toUpperCase();
void main(){
capitalizeName('dart');
capitalizeName(null);
}
위처럼 String? 를 이용하여 코드를 작성하면 null 부분에서는 오류가 나지 않지만, null일 수도 있는 값에 toUpperCase()를 호출할 수 없기 때문에 오류가 난다.
String capitalizeName(String? name) {
if (name != null){
return name.toUpperCase();
}
return 'ANON';
}
void main(){
capitalizeName('dart');
capitalizeName(null);
}
if문을 작성하여 null이 아닌 경우에만 함수가 실행되도록 다음과 같이 작성할 수 있다.
이를 더 간단히 작성할 수 있는 방법이 있는데 fat arrow를 사용하는 것이다.
String capitalizeName(String? name) => name != null ? name.toUpperCase() : 'ANON';
void main(){
capitalizeName('dart');
capitalizeName(null);
}
물론 더 짧아졌지만 동일하게 실행되기 때문에 결과 값은 같다. name이 null이 아니 nametoUpperCase()를 return하고 null이라면 'ANON' 을 return한다.
이를 더 간단하게 줄이는 법이 바로 QQ Operator이다.
QQ(question question) Operator
left ?? reight
좌항이 null 이면 우향을 return 한다.
좌항이 null이 아니라면 그대로 좌항을 return 한다.
String capitalizeName(String? name) => name.toUpperCase() ?? 'ANON';
void main(){
capitalizeName('dart');
capitalizeName(null);
}
하지만 이 경우에도 오류가 나는데, 그 이유는 name 자체가 null인 경우 toUpperCase를 호출 할 수 없기 때문이다.
String capitalizeName(String? name) => name?.toUpperCase() ?? 'ANON';
void main(){
capitalizeName('dart');
capitalizeName(null);
}
이 경우 name 뒤에 ?를 붙여 쉽게 해결 할 수 있다.
QQ equals / QQ assignment operator
void main(){
String? name;
name ??= 'dart';
name ??= 'another';
print(name);
}
다음 코드를 실행 하면 dart라는 결과와 경고가 함께 출력된다. 이는 당연한 것인데, name이 dart라는 값을 받은 이후에는 null이 될 일이 없기 때문이다.
void main(){
String? name;
name ??= 'dart';
name = null;
name ??= 'another';
print(name);
}
중간에 null을 넣어주면 경고 없이 another이 출력되는 것을 확인 할 수 있다.
#3.5 Typedef
자료형이 헷갈릴 때 도움이 될 alias를 만드는 방법이다.
숫자로 된 List를 반대로 뒤집어서 return 하는 함수를 만들 때
List<int> reverseListOfNumbers(List<int> list){
var reversed = list.reversed;
return reversed.toList();
}
void main(){
}
다음과 같이 작성 할 수 있다. typedef를 이용하면 긴 코드에서 더 유용하게 사용 할 수 있으며, 해당 코드에서는 사용하면 아래와 같다.
typedef ListofInt = List<int>;
ListofInt reverseListOfNumbers(ListofInt list){
var reversed = list.reversed;
return reversed.toList();
}
void main(){
print(reverseListOfNumbers([1,2,3]));
}

결과가 잘 실행되는 것도 확인 할 수 있다.
Map의 typedef를 만들고 싶을 수 있다. 예를 들어 사용자에게 인사하는 함수를 만드는데, 사용자가 함수에게 주는 값이 더 구체적으로 구조를 만들고 싶은 경우인데,
typedef UserInfo = Map<String, String>;
String sayHi(UserInfo userInfo){
return "Hi${userInfo['name']}";
}
void main(){
sayHi({"name": 'dart'});
}
만약 구조화된 데이터의 형태를 지정하고 싶다면 class를 제작해야 한다.