1. final과 const
1) final 과 const 선언
final 과 const 는 아래와 같은 방식으로 선언한다.
final double pi = 3.141592;
const double e = 2.71828;
2) final과 const 공통점, 차이점
final과 const 공통점
- 한 번 설정한 값을 변경할 수 없다. (다른 값으로 변경하려고 시도하면 컴파일 오류가 발생)
final & const 차이점
- const의 경우, 컴파일 타임에서 상수를 정의할 수 있다. 즉, const로 정의한 상수는 런타임에서 정의되는 값을 설정할 수 없다는 의미다.
- 예를 들어, DateTime.now()의 경우 런타임에서 호출 될 때마다 결과 값이 다른데 이러한 값은 const로 설정할 수 없다.
- final은 런타임에서 결정되는 값도 설정할 수 있다.
final DateTime now = DateTime.now(); // 문제 없음
// const DateTime now = DateTime.now(); // compile error
위 코드에서 const DateTime now = DateTime.now(); 코드는 final에서는 문제없지만, const의 경우 오류를 발생시킨다.
예시)
final과 const는 배열을 선언하는 과정에서 또 다른 차이점을 발견할 수 있다.
final List<String> languages = [];
const List<String> companies = [];languages.add('dart');
/*
// compile error
companies.add('Google');
languages = ['Java'];
*/
languages는 final 로 선언되어 있음에도 불구하고 배열에 값을 추가할 수 있지만, const 로 선언된 companies 배열에는 값을 추가할 수 없다.
대신 두 배열 모두 새로운 배열로 변경하는 것은 불가능하다. 결국 final 로 선언된 변수는 해당 변수에 새로운 값이 설정되는 것은 불가능하지만, 객체나 배열에 값을 추가하는 행위에 대해서는 관여하지 않는다는 것을 확인 할 수 있다.
2. generics
1) Generics의 개념
: <>으로 타입을 지정할 수 있다. 이는 flutter개발을 하면서 자주 접할 수 있다. 대표적으로 많이 활용되는 부분에는 List를 정의할 때 많이 활용한다.
List<String>
List<int>
2) Generics를 왜 사용하는 것인가?
타입 안정성, Type Safety 를 위해서 사용한다. 다시 말해, class의 Type을 안전하게 사용하기 위한 목적이다.
예를 들어,
List list = [];
Generics라는 것이 없다고 가정할 때, 위와 같이 리스트를 선언했다고 가정해보자. 그렇다면 위의 list는 타입이 지정되어있지 않기 때문에 자유롭게 String이나 int 혹은 custom class 등을 넣을 수 있게 된다.
list.add(1);
list.add(3);
list.add(5);
list.add(7);
그래서 어떤 개발자가 초반에 int만을 사용할 목적으로 위의 list 를 만들었다고 하면, 시간이 지나 유지보수를 하다가 다른 곳에서 위의 list 데이터를 접근해서 데이터를 넣어야 하는 상황이 된다면, int 타입이 아닌 String 타입을 넣어주게 된다고 생각해보자.
list.add("2");
이렇게 코드가 작성이 되며 코드상 문제가 발생하지 않게 된다 이유는 모든 유형을 받을 수 있는 list로 선언 되었기 때문이다.
int sum = 0;
list.forEach((element) {
sum += (element as int);
});
print(sum);
list의 모든 데이터를 합하는 연산 작업이 있다고 한다면 문제가 러닝타임 때에 발생하게 된다. 위 로직에서 Type casting 오류가 발생하게 된다.
var list = <int>[];
💡 명확하게 int 타입을 지정하게 되면서 다른 유형의 데이터를 list 안에 담으려고 할 때에 오류를 보여주게 되면서 개발자가 실수를 하지 못하도록 만들어 주게 된다. 이것이 바로 제네릭이 Type Safety의 목적을 두고 있다는 점입니다.
3. Future
1) Future의 개념
Dart에서의 Future는 자바스크립트에서의 Promise에 대응된다. Future와 Promise는 모두 싱글스레드 환경에서 비동기 처리를 위해 존재한다.
- JS의 Promise는 특정 동작의 수행이 완료되면 다음 동작을 수행하겠다는 약속
- Dart의 Future는 지금은 없지만 미래에 요청한 데이터 혹은 에러가 담길 그릇
2) async / await
async / await 또한 Dart 의 비동기 처리를 위한 것으로 Future를 조금 더 용이하게 다루기 위한 키워드이다. 이를 사용하기 위해서는 규칙이 있다.
- await 키워드를 사용한 함수는 무조건 async 함수이어야 합니다.
- async 함수는 무조건 Future 를 반환해야 합니다.
2-1) 첫번째 규칙
Future functionName() async {
...
await someFunction();
...
}
await라는 키워드를 함수 내부에서 사용한다면 해당 함수 스코프를 알려주는 {}의 앞에 async를 적어줘야 한다.
2-2) 두번째 규칙
return 타입은 Future<String>이므로 future의 타입은 String으로 바뀌는 것이 아닌 계속 Future<String>이다.
async / await 을 쓰는 이유
: future을 쓰게 되면 then과 함께 쓰이게 되는데, 이렇게 되면 코드가 길어지게 된다. 그러면서 가독성이 안 좋게 된다. 그래서 async / await를 써서 가독성이 좋게 만들고, 더 간결하게 만드는 것이다. 결론적으로 future의 사용을 더 용이하게 해준다.
🔗 참고
https://medium.com/dartlang-korea/dart-final-과-const-bc8c6c024ef4
https://sudarlife.tistory.com/entry/Flutter-플러터-제네릭-제네릭-하는데-그게-뭐야-개념-살펴보기
https://velog.io/@jintak0401/FlutterDart-에서의-Future-asyncawait