기본적인 구성요소를 아라보자
https://webapp.chatgpt4google.com/s/Mjc1MzMw
모든 Dart 프로그램의 Entry Point(진입점)
즉, 필수로 가져야할 함수
꼭 가져야할 함수다. 없으면 아래와 같이 오류가 뜬다.
void main() {
print('Hello World');
}
JS 같은 곳에서 오토로 달아주지 않았는가? 근데 Dart는 공백이나 앞 여백을 Formatting 해주는 기능은 있지만 세미콜론을 자동으로 달아주는 기능이 없기에 필수로 달아줘야한다. 특히 나같은 JS, TS 쟁이들은 조심해야한다.
가장 기본인 변수 선언 및 할당하는 법을 Araboza.
재할당이 가능한 var
선언자다.
void main() {
var name = '뿔소';
}
우리 JS, TS 쟁이들에게 익숙한 var
를 쓴다. 원래 다트도 정적 타입 언어인데, TS같이 타입도 추론해서 해주기 때문에 따로 타입을 지정해주지 않는 모습이다. 즉, 동적 타입(dynamic)를 지원하는 정적 타입 언어인 셈.
타입으로 선언할 수 있다.
void main() {
String name = '뿔소';
}
이렇게 사용이 가능하지만 dart에서는 차피 추론해서 알아서 해주기 때문에 var로 하는 것을 더 권장한다.
타입 선언자 방식은 나중에 class
의 property
를 작성할 때 사용하는 것을 권장한다.
업데이트할 수 있다. 당연한 소리지만 같은 타입만 가능하다.
void main() {
var name = '뿔소';
name = '윤뿔소';
name = '1';
}
dart에 있는 신기한 기능이다. 개발하다보면 어쩔 수 없을 땐 동적 타입을 써야할 때도 있다. 다트는 정적 타입을 기본으로 하지만 개발자 친화적이라 동적 타입으로 선언하는 것을 지원하기도 한다.
void main() {
// dynamic name;도 가능
var name;
name = '뿔소';
name = 12;
name = true;
}
위 사진과 코드를 보면은 타입이 dynamic
으로 선언된 걸 볼 수 있다. 그리고 위 var
에서 선언됐던과는 달리 타입 여러가지를 받는 모습을 볼 수 있다.
단점은 각 타입만의 활용법을 쓰는 것이 좀 불편해진다.
사진과 같이 메소드가 별로 없다. 그러면 그 타입으로 활용하고 싶다면 if문을 만들어 분기점을 나누면 된다.
위 사진처럼 String
이라는 조건문 안에서 .을 박았을 때 메소드가 많이 나오는 걸 볼 수 있다.
이런 단점들이 있기에 정말 정말 필요할 때 쓰자.
개발할 때 null
관련한 오류를 많이 보지 않았는가?
이것처럼 말이다. 리액트에서 null
값을 참조할 때 많이들 생기는 오류다. null
값을 참조해버리면 컴파일러가 캐치하지못하는, 치명적인 런타임 오류가 생기기 때문에 런타임 실행 전 미리 막아두는 것이다.
dart도 그런 의미에서 Null Safety라는 기능이 있다. null
을 미리 참조하지 못하게 런타임 전에, 애초에 문법 오류로 막는 것이다.
그래서 다트에서는 변수 선언할 때 모든 변수가 non-nullable
한다고 생각하면서 실행된다. 그래서 어떤 변수가 null
이라면 오류가 나는 것. 그러면 어떻게 해야할까?
TS 쟁이들은 타입 선언하며 많이 써왔겠지만 타입 선언자에 ?
를 쓰면 된다. 예시를 보자.
void main() {
String name = '뿔소';
name = null;
}
그냥 이렇게 쓰면 아래처럼 오류가 난다.
void main() {
String? name = '뿔소';
name = null;
}
이렇게 쓰면 된다. 이제 다트에서 null
이란 걸 알았기에 도와주려고 노력한다. 예를 들어 메소드 length
를 쓰려고 하면
'null
이 될 수 있는 곳에 length
쓰면 안돼잉' 하고 오류를 써주기 때문에 우리는 if문이나 null
을 걸러주는 ?
이나 !
를 쓰면 된다.
void main() {
String? name = '뿔소';
name = null;
// 1
if (name != null) {
name.length;
}
// 2
name?.length;
// 3
name!.length;
}
즉 Nullable Variables를 선언하는 이유는 'null
이 될 수 있는 곳에 명시적으로 기록하고, 추적하게 만들어줘서' 인 거시다.
특히! API에서 data를 불러오는 곳에 많이 쓰이니 잘 알아두자.
var도 가능하다. 즉, var?
형식으로 변수를 선언하면 해당 변수는 null
을 허용하는 타입으로 지정됩니다. 하지만, null
도 받아줘야 되므로이 경우 컴파일러가 자동으로 유추하는 타입은 dynamic?
이므로, 보다 정확한 타입을 선언하려면 명시적으로 타입 지정자 (예 : String?
, int?
) 를 사용해야 한다.
따라서, var
키워드를 사용할 때 null safety를 표시하려면 var?
을 사용하면 되지만, 타입이 명확하지 않을 경우에는 보다 정확한 타입 지정을 위해 타입 지정자를 함께 사용하는 것이 권장된다.
TS에선 const
같이 상수를 만들어 수정되지 않는 변수를 만들어서 용도를 구분해 선언했다. dart도 똑같이 그런 기능을 가진 선언자가 있다. 함 보자.
final
이라는 선언자로 한다.
void main() {
final name = '뿔소';
name = null; // 에러
}
위 사진처럼 1번만 쓸 수 있다고 에러가 뜬다. 즉, 누구도 이 변수를 수정하지 못한다는 것.
와! 익숙한 단어 아닌가? 아니다. JS, TS의 const
완 다른 역할을 지닌다. 오히려 다트의 final
과 JS, TS의 const
가 같은 느낌이랄까.
dart에서 const
는 compile-time constant
를 만들어 준다. 무슨 말임;; 알아보자.
void main() {
const name = '뿔소';
name = "뿔소";
}
final과 똑같이 재선언이 불가하긴 한다. 근데 가장 큰 차이점은 compile-time, 즉 컴파일할 때! 이 변수의 값이 존재해야만 한다. 안그러면 오류가 뜬다.
펫칭할 데이터가 있다고 가정하자. const
에 그걸 넣는다면 대부분 에러가 날 것이다.
왜냐! 펫칭 데이터는 비동기적으로 가져온다고 알고 있지 않는가? 근데 렌더링 됐을 때는 그 데이터가 없기에 에러가 뜰 것이다. 나중이든 언제든 렌더링 되기 전에는 무조건 값이 할당돼야 한다는 것. 그게 const
의 역할이다.
앱스토어에 올리기 전에 이미 알고 있는 값을 다룰 때 좋을 것이다. 예를 들면 max_allowed_price
같은 게 있을 것이다. 앱에서 사용할 상수들이 있다면 이렇게 const
를 써주면 된다.
초기 데이터 없이 변수를 선언할 수 있게 해주는 수식어구다.
dart의 아주 재밌고 신기한 기능이다. var
같은 변수 선언자 앞에 쓸 수 있다.
void main() {
late final String name;
// 무언갈 해줌, api 호출 후 비동기적으로 데이터 받아와주면 할당해주면 됨.
name = "뿔소";
}
이런 식으로 말이다. 그렇다면 그 전에 name
변수를 이용해서 실행시키는 등의 행위를 시킨다면?
위 사진과 같이 오류가 뜬다. late
변수가 제대로 선언받지 못했다고.
즉, dart는 name
이 late
변수이기 때문에 값을 넣기 전에는 접근하지 않아야 한다는 걸 알려준다. Null Safety를 우리가 직접 만드는 느낌인 거시다.
이 수식어도 data를 fetching 해올 때 진짜 유용하게 쓰인다. API에서 얻어온 값을 써야할 때, 저렇게 쓰고 late
를 붙인다면 펫징 후에 쓸 수 있도록 자리를 만들어주는 것이다.
var
, dynamic
, ?(nullable)
, final
, const
, late
이렇게 총 6가지의 변수 선언 유형을 알아보았다. 차이점을 암기하기보단 이해하려고 노력하자.
재선언 가능, non-nullable, 타입 지켜주기
void main() {
int i = 12;
var name = '윤뿔소';
i = 1212121212;
name = '뿔소';
}
동적 타입으로 선언하기, 아무 때나 쓰지 말기, 활용하고 싶다면 if문을 써서 타입 분기점 나누기
void main() {
// dynamic name;도 가능
var name;
name = '뿔소';
name = 12;
name = true;
}
공통점은 1번만 할당 가능-late
를 쓰더라도 나중에 한번만 할당 가능
차이점은 final
은 렌더링 시 값이 없어도 오류 X, const
는 없으면 오류 O
void main() {
final name = '뿔소';
const api_key = '1231231231312';
// 가능
late final String api_data;
api_data = '뿔소소';
// 에러
const nameee;
}
예시를 보면 알겠지만 주로 웹/앱 정보를 미리 담아야한다면 const
, 값이 나중에 와도 상관 없지만 변하지 않는 걸 선언해주고 싶다면 final
이다.
null safety는 잘못된 상태의 변수를 참조하는 것을 막아줌. 덕분에 모든 변수는 non-nullable. nullable하게 만들고 싶으면 ?
를 붙임
void main() {
String? name = '뿔소';
name = null;
// error: null인 걸 dart에서 알려줬음
name.isEmpty;
// Good
if (name != null) {
name.isEmpty;
}
name?.isEmpty;
name!.isEmpty;
}
dart한테 아직은 어떤 데이터가 올지 모른다고 말해주는 것. 데이터를 넣기 전엔 사용 불가라고 알려줌. 편함!
void main() {
late final String name;
// 무언갈 해줌, api 호출 후 비동기적으로 데이터 받아와주면 할당해주면 됨.
// error
print(name);
// Good
name = "뿔소";
print(name);
}
와. 스크롤 압박. 요약이 거의 본문 길이랑 비슷한데요? ㅋㅋㅋㅋㅋㅋㅋ