void main() {
print("hello, world");
}
main 함수는 모든 Dart의 Entry Program이다. main 함수에서 내가 작성한 코드가 호출되기 때문에 반드시 작성되어야 한다.
또한, 세미콜론이 필수인 언어이다. js처럼 formatter가 자동으로 세미콜론을 달아주지 않는데, 그 이유는 dart에서는 일부러 세미콜론은 안 쓸 때가 있기 때문이다. (cascade operator 때문 !)
변수에 대해 알아보자.
dart에서는 변수를 만드는 방법이 두 가지 있다.
void main() {
var name = '주삐';
}
먼저 var에 대해 알아보자. 위에서 선언한 변수를 보면, 변수의 타입을 구체화하지 않았다. 왜냐면 dart 컴파일러가 타입을 알아서 추론할 수 있기 때문에 !
위 변수는 업데이트될 수 있고, 업데이트 시 할당하는 값은 변수의 본래 타입과 일치해야한다.
다른 하나의 방법은 변수 선언시 아래처럼 타입을 명시적으로 선언해주는 것이다.
void main(){
String name = '주삐';
}
그렇다면 이 다른 두 가지 방법을 각각 언제 써야할까?
관습적으로 함수나 메소드 내부에 지역 변수를 선언할 때는 var를 사용하며, class에서 변수나 property를 선언할 때에는 var 키워드를 사용하지 않고 타입을 지정해준다.
dynamic type은 dart의 개발자 친화적인 특징을 보여준다.
void main(){
var name;
// dynamic name;
name = '주삐';
name = 62;
name = true;
}
변수 선언시, 초기화를 해주지 않으면 이는 다이나믹 타입으로 인식되어서 다양한 타입으로 업데이트가 가능하다.
이러한 기능을 제공하는 이유는 뭘까 ?
우선, 변수가 어떤 타입을 가지게 될지 미리 알기 어려운 경우가 있기 때문이고, 가끔 dynamic 이 더 유용할 수 있기 때문이다.
null safety에 대해 알아보자.
null safety란 개발자가 null 값을 참조할 수 없도록 하는 것이다. 만약 코드에서 null 값을 참조하게 된다면 runtime error가 발생하기 때문에 이를 사전에 방지하는 것이 중요한데, null safety가 하는 일이 이것이라고 생각하면 된다.
dart 초기 버전에는 null safety를 지원하지 않다가, 나중에 나오게 되었다. dart 에서 null safety를 어떻게 지원하는지 보자.
bool isEmpty(String string) => string.length == 0;
패ㅑㅇ main() {
isEmpty(null);
}
null safety가 지원되지 않는 버전의 dart에서 위 코드를 실행하게 되면 런타임 에러가 난다. (NoSuchMethod
)
string을 보내야하는 곳에 null을 보냈기 때문이다. null에는 length라는 속성이 없기 때문에 에러가 발생한다. 그리고 해당 에러는 사용자의 기기에서 발생하는 에러이기 때문에 컴파일러 사전에 방지할 수 없다.
이걸 어떻게 해결할 수 있을까 ?
dart에서는 어떤 변수가 null이 될 수 있음을 정확히 표시해야한다.
void main() {
String name = '주삐';
// name = null;
String? name = '주삐';
name = null;
}
타입 뒤에 ?
를 붙여서 해당 변수가 null을 가질 수도 있다는 것을 dart (정확히는 컴파일러)가 알 수 있게 해야한다.
void main() {
String? name = '주삐';
name = null;
// name.length;
}
위 주석 처리된 부분의 코드는 name이 null 일 수도 있기 때문에 컴파일러 타입을 확인하라고 빨간 줄을 그어준다.
void main() {
String? name = '주삐';
name = null;
if (name != null) {
name.isNotEmpty;
}
// name?.isNotEmpty;
}
위 코드는 name이 null이 아닐때만 실행되도록 조건 처리를 해줬기 때문에 컴파일러가 통과시켜준다.
정리하자면, dart의 null safety란 어떤 변수 혹은 데이터가 null이 될 수 있음을 명시하는 것을 말한다
기본적으로 모든 변수는 non-nullable이기 때문에, nullable data는 꼭 ?
를 사용해서 null이 될 수 있음을 명시해줘야 한다.
var 키워드를 사용하던, 명시적인 타입을 사용해서 선언하던, 둘 다 나중에 변경될 수 있는 변수가 만들어진다.
변경되지 않은 변수를 선언하려면 final 키워드를 사용하면된다. (js의 const와 동일)
void main() {
final String name = '주삐';
// final name = '주삐';
}
late는 final이나 var 앞에 붙여줄 수 있는 수식어다.
void main() {
late final String name;
// do something, go to api
}
late는 초기 데이터없이 변수를 선언할 수 있게 해준다. 선언 후 api 요청 등으로 받아온 데이터를 저장할 수 있다.
좋은 점은 late 키워드가 붙은 변수에는 값이 할당되기 전에 접근하고 있는지 컴파일러가 판단해서 알려준다. 값을 넣어야 사용할 수 있기 때문에 flutter에서 data fetching 시에 굉장히 유용하다.
dart의 const 키워드는 js, ts에서의 const와 다르다.
js, ts의 const는 dart의 final과 비슷하다.
dart에서 const는 compile-time constant를 만들어준다. compile-time 에 알고 있는 값이어야 한다는 것이다. (api key를 저장한다거나 할 때 사용할 수 있음)