코드팩토리의 플러터 프로그래밍 (책_기본문법)
Map 타입
맵 타입은 키와 값의 짝을 저장한다. 순서대로 값을 저장하는데 중점을 두는 리스트와 달리 키를 이용해서 원하는 값을 빠르게 찾는데 중점을 둔다.
Map<키의 타입, 값의 타입> 맵이름 형식으로 생성한다.
void main() {
Map<String, String> dictionary = {
'Harry Potter':'해리 포터',
'Ron Weasley':'론 위즐리',
'Hermione Granger':'헤르미온느 그레인저',
};
print(dictionary['Harry Potter']); // 해리 포터
print(dictionary['Hermione Granger']); // 헤르미온느 그레인저
}
키와 값 반환받기
void main() {
Map<String, String> dictionary = {
'Harry Potter':'해리 포터',
'Ron Weasley':'론 위즐리',
'Hermione Granger':'헤르미온느 그레인저',
};
print(dictionary.keys); // (Harry Potter, Ron Weasley, Hermione Granger)
// Iterable이 반환되기 때문에 .toList()를 실행해서 List를 반환받을 수도 있음
print(dictionary.values); // (해리 포터, 론 위즐리, 헤르미온느 그레인저)
}
Set타입
set은 중복 없는 값들의 집합이다. Set<타입> 세트이름 형식으로 생성되고 중복없는 유일한 값들만 존재하는걸 보장한다.
void main() {
Set<String> blackPink = {'로제','지수','리사','제니','제니'}; // 1 제니 중복
print(blackPink); // {로제, 지수, 리사, 제니}
print(blackPink.contains('로제')); // 2 값이 있는지 확인하기 true
print(blackPink.toList()); // 3 리스트로 변환하기 [로제, 지수, 리사, 제니]
List<String> blackPink2 = ['로제','지수','지수'];
print(Set.from(blackPink2)); // 4 List 타입을 Set 타입으로 변환 {로제, 지수}
}
contains()함수를 사용하면 값이 있는지 없는지 불리언으로 출력된다.
List타입으로 변환하거나 List를 Set타입으로 변환할 수 있고 변환되면서 중복값을 체크해서 변환된다.
컬렉션 타입은 타입 그 자체로도 다채로운 자료 형태를 표현할 수 있다. 최대 장점은 서로의 타입으로 형변환을 하며 나타낸다.
Map타입의 키와 값을 따로 리스트로 받아보고 싶아면 .Keys.toList()와 .values.toList함수를 사용할 수있다.
Set.From()을 사용하면 어떤 리스트든 Set타입으로 변환할 수 있다.
enum
이넘은 한 변수의 값을 몇가지 옵션으로 제한하는 기능이다. 선택지가 제한적일 떄 사용한다.
String으로 완전 대체할 수 있찌만 enum은 기본적으로 자동 완성이 지원되고 정확히 어떤 선택지가 존재하는지 정의해둘 수 있다.
enum Status {
approved,
pending,
rejected,
}
void main() {
Status status = Status.approved;
print(status); // Status.approved
}
연산자
null 관련 연산자
다트 언어에서는 변수 타입이 null값을 가지는지 여부를 직접 지정해줘야 한다.
타입 키워드를 그대로 사용하면 기본적으로 null 값이 저장될 수 없고, 타입 뒤에 '?'를 추가해줘야 저장된다.
void main() {
// 타입 뒤에 ?를 명시해서 null값을 가질 수 있습니다.
double? number1 = 1;
// 타입 뒤에 ?를 명시하지 않아 에러가 납니다.
double number2 = null;
}
값 비교 연산자
void main() {
int number1 = 1;
int number2 = 2;
print(number1 > number2); // false
print(number1 < number2); // true
print(number1 >= number2); // false
print(number1 <= number2); // true
print(number1 == number2); // false
print(number1 != number2); // true
}
타입 비교 연산자
void main() {
int number1 = 1;
print(number1 is int); // true
print(number1 is String); // false
print(number1 is! int); // false. !는 반대를 의미합니다(int 타입이 아닌 경우 true).
print(number1 is! String);// true
}
함수와 람다
함수의 일반적인 특징
함수는 여러 곳에서 재활용 할 수 있고, 반환할 값이 없을 떄는 void 키워드를 사용한다.
네임드 파라미터를 지정하려면 중괄고 { }와 required 키워드를 사용해야 한다.
int addTwoNumbers({
required int a,
required int b,
}) {
return a + b;
}
void main() {
print(addTwoNumbers(a: 1, b: 2));
}
여기서 required키워드는 매개변수가 null값이 불가능한 타입이면 기본값을 지정해주거나 필수로 입력해야 한다는 의미이다.
기본값을 갖는 포지셔널 파라미터는 [ ] 기호를 사용하면 된다.
int addTwoNumbers(int a, [int b = 2]) {
return a + b;
}
void main() {
print(addTwoNumbers(1));
}
네임드 파라미터에 기본값을 적용할때는 required키워드를 생략해주고 등호 다음에 원하는 기본값을 입력해주면 된다.
int addTwoNumbers({required int a,int b = 2,}) {
return a + b;
}
void main() {
print(addTwoNumbers(a: 1));
}
포지셔널 파라미터와 네임드 파라미터를 섞어도 사용할 수 있다. 섞어 사용할 때는 포지셔널 파라미터가 네임드 파라미터보다 반드시 먼저 위치해야 한다.
int addTwoNumbers(int a, {required int b,int c = 4,}) {
return a + b + c;
}
void main() {
print(addTwoNumbers(1, b: 3, c: 7));
}
익명 함수와 람다 함수
이 둘은 함수 이름이 없고 일회성으로 사용된다는 공통점이 있다.
익명 함수에서 {}를 빼고 => 기호를 추가한 것이 람다 함수이다. 람다는 함수 로직을 수행하는 스테이트먼트가 딱 하나이여야 한다.
콜백 함수나 리스트의 map, reduce, fold함수 등에서 일회성이 높은 로직을 작성할 떄 주로 사용한다.
// 익명 함수
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
// 일반 함수로 모든 값 더하기
final allMembers = numbers.reduce((value, element) {
return value + element;
});
print(allMembers);
}
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
// 람다 함수로 모든 값 더하기
final allMembers = numbers.reduce((value, element) => value + element);
print(allMembers);
}
typedef와 함수
typedef 키워드는 함수의 시그니처를 정의하는 값으로 보면 된다.
여기서 시그니처는 반환값 타입, 매개변수 개수와 타입 등을 말한다. 즉 함수 선언부를 정의하는 키워드라 함수가 무슨동작을 하는지에 대한 정의는 없다.
typedef Operation = void Function(int x, int y);
이다음엔 시그니처에 맞춘 함수를 만들어서 사용하면 된다.
typedef Operation = void Function(int x, int y);
void add(int x, int y) {
print('결괏값 : ${x + y}');
}
void subtract(int x, int y) {
print('결괏값 : ${x - y}');
}
void main() {
// typedef는 일반적인 변수의 type처럼 사용 가능
Operation oper = add;
oper(1, 2);
// subtract() 함수도 Operation에 해당되는
// 시그니처이므로 oper 변수에 저장 가능
oper = subtract;
oper(1, 2);
}
typedef Operation = void Function(int x, int y);
void add(int x, int y) {
print('결괏값 : ${x + y}');
}
void calculate(int x, int y, Operation oper) {
oper(x, y);
}
void main() {
calculate(1, 2, add);
}