Dart 기본 문법 : 변수

윤뿔소·2023년 4월 3일
1

Dart / Flutter

목록 보기
2/18

기본적인 구성요소를 아라보자
https://webapp.chatgpt4google.com/s/Mjc1MzMw

main 함수

모든 Dart 프로그램의 Entry Point(진입점)
즉, 필수로 가져야할 함수

꼭 가져야할 함수다. 없으면 아래와 같이 오류가 뜬다.

예시

void main() {
  print('Hello World');
}

세미콜론 필수

JS 같은 곳에서 오토로 달아주지 않았는가? 근데 Dart는 공백이나 앞 여백을 Formatting 해주는 기능은 있지만 세미콜론을 자동으로 달아주는 기능이 없기에 필수로 달아줘야한다. 특히 나같은 JS, TS 쟁이들은 조심해야한다.

변수 만드는 법

가장 기본인 변수 선언 및 할당하는 법을 Araboza.

var 키워드

재할당이 가능한 var 선언자다.

void main() {
  var name = '뿔소';
}

우리 JS, TS 쟁이들에게 익숙한 var를 쓴다. 원래 다트도 정적 타입 언어인데, TS같이 타입도 추론해서 해주기 때문에 따로 타입을 지정해주지 않는 모습이다. 즉, 동적 타입(dynamic)를 지원하는 정적 타입 언어인 셈.

타입으로 선언

타입으로 선언할 수 있다.

void main() {
  String name = '뿔소';
}

이렇게 사용이 가능하지만 dart에서는 차피 추론해서 알아서 해주기 때문에 var로 하는 것을 더 권장한다.

타입 선언자 방식은 나중에 classproperty를 작성할 때 사용하는 것을 권장한다.

var 선언 변수 재할당

업데이트할 수 있다. 당연한 소리지만 같은 타입만 가능하다.

void main() {
  var name = '뿔소';
  name = '윤뿔소';
  name = '1';
}

dynamic 선언

dart에 있는 신기한 기능이다. 개발하다보면 어쩔 수 없을 땐 동적 타입을 써야할 때도 있다. 다트는 정적 타입을 기본으로 하지만 개발자 친화적이라 동적 타입으로 선언하는 것을 지원하기도 한다.

void main() {
  // dynamic name;도 가능
  var name;
  name = '뿔소';
  name = 12;
  name = true;
}

위 사진과 코드를 보면은 타입이 dynamic으로 선언된 걸 볼 수 있다. 그리고 위 var에서 선언됐던과는 달리 타입 여러가지를 받는 모습을 볼 수 있다.

dynamic 단점

단점은 각 타입만의 활용법을 쓰는 것이 좀 불편해진다.

사진과 같이 메소드가 별로 없다. 그러면 그 타입으로 활용하고 싶다면 if문을 만들어 분기점을 나누면 된다.

위 사진처럼 String이라는 조건문 안에서 .을 박았을 때 메소드가 많이 나오는 걸 볼 수 있다.

이런 단점들이 있기에 정말 정말 필요할 때 쓰자.

Nullable Variables

개발할 때 null 관련한 오류를 많이 보지 않았는가?

이것처럼 말이다. 리액트에서 null 값을 참조할 때 많이들 생기는 오류다. null 값을 참조해버리면 컴파일러가 캐치하지못하는, 치명적인 런타임 오류가 생기기 때문에 런타임 실행 전 미리 막아두는 것이다.

Null Safety

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도 가능하다. 즉, var? 형식으로 변수를 선언하면 해당 변수는 null을 허용하는 타입으로 지정됩니다. 하지만, null도 받아줘야 되므로이 경우 컴파일러가 자동으로 유추하는 타입은 dynamic?이므로, 보다 정확한 타입을 선언하려면 명시적으로 타입 지정자 (예 : String?, int?) 를 사용해야 한다.

따라서, var 키워드를 사용할 때 null safety를 표시하려면 var?을 사용하면 되지만, 타입이 명확하지 않을 경우에는 보다 정확한 타입 지정을 위해 타입 지정자를 함께 사용하는 것이 권장된다.

수정이 안되는 변수 만들기

TS에선 const 같이 상수를 만들어 수정되지 않는 변수를 만들어서 용도를 구분해 선언했다. dart도 똑같이 그런 기능을 가진 선언자가 있다. 함 보자.

final

final이라는 선언자로 한다.

void main() {
  final name = '뿔소';
  name = null;  // 에러
}

위 사진처럼 1번만 쓸 수 있다고 에러가 뜬다. 즉, 누구도 이 변수를 수정하지 못한다는 것.

const

와! 익숙한 단어 아닌가? 아니다. JS, TS의 const완 다른 역할을 지닌다. 오히려 다트의 final과 JS, TS의 const가 같은 느낌이랄까.

dart에서 constcompile-time constant를 만들어 준다. 무슨 말임;; 알아보자.

void main() {
  const name = '뿔소';
  name = "뿔소";
}

final과 똑같이 재선언이 불가하긴 한다. 근데 가장 큰 차이점은 compile-time, 즉 컴파일할 때! 이 변수의 값이 존재해야만 한다. 안그러면 오류가 뜬다.

펫칭할 데이터가 있다고 가정하자. const에 그걸 넣는다면 대부분 에러가 날 것이다.
왜냐! 펫칭 데이터는 비동기적으로 가져온다고 알고 있지 않는가? 근데 렌더링 됐을 때는 그 데이터가 없기에 에러가 뜰 것이다. 나중이든 언제든 렌더링 되기 전에는 무조건 값이 할당돼야 한다는 것. 그게 const의 역할이다.

앱스토어에 올리기 전에 이미 알고 있는 값을 다룰 때 좋을 것이다. 예를 들면 max_allowed_price 같은 게 있을 것이다. 앱에서 사용할 상수들이 있다면 이렇게 const를 써주면 된다.

late 수식어

초기 데이터 없이 변수를 선언할 수 있게 해주는 수식어구다.

dart의 아주 재밌고 신기한 기능이다. var같은 변수 선언자 앞에 쓸 수 있다.

void main() {
  late final String name;
  // 무언갈 해줌, api 호출 후 비동기적으로 데이터 받아와주면 할당해주면 됨.
  name = "뿔소";
}

이런 식으로 말이다. 그렇다면 그 전에 name 변수를 이용해서 실행시키는 등의 행위를 시킨다면?

위 사진과 같이 오류가 뜬다. late 변수가 제대로 선언받지 못했다고.

즉, dart는 namelate 변수이기 때문에 값을 넣기 전에는 접근하지 않아야 한다는 걸 알려준다. Null Safety를 우리가 직접 만드는 느낌인 거시다.

이 수식어도 data를 fetching 해올 때 진짜 유용하게 쓰인다. API에서 얻어온 값을 써야할 때, 저렇게 쓰고 late를 붙인다면 펫징 후에 쓸 수 있도록 자리를 만들어주는 것이다.


요약

var, dynamic, ?(nullable), final, const, late

이렇게 총 6가지의 변수 선언 유형을 알아보았다. 차이점을 암기하기보단 이해하려고 노력하자.

var

재선언 가능, non-nullable, 타입 지켜주기

void main() {
  int i = 12;
  var name = '윤뿔소';
  i = 1212121212;
  name = '뿔소';
}

dynamic

동적 타입으로 선언하기, 아무 때나 쓰지 말기, 활용하고 싶다면 if문을 써서 타입 분기점 나누기

void main() {
  // dynamic name;도 가능
  var name;
  name = '뿔소';
  name = 12;
  name = true;
}

final, const

공통점은 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이다.

?(nullable)

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; 
}

late

dart한테 아직은 어떤 데이터가 올지 모른다고 말해주는 것. 데이터를 넣기 전엔 사용 불가라고 알려줌. 편함!

void main() {
  late final String name;
  // 무언갈 해줌, api 호출 후 비동기적으로 데이터 받아와주면 할당해주면 됨.
  // error
  print(name);
  // Good
  name = "뿔소";
  print(name);
}
profile
코뿔소처럼 저돌적으로

5개의 댓글

comment-user-thumbnail
2023년 4월 8일

와. 스크롤 압박. 요약이 거의 본문 길이랑 비슷한데요? ㅋㅋㅋㅋㅋㅋㅋ

답글 달기
comment-user-thumbnail
2023년 4월 8일

요약까지 있어서 편하게 배우고 갑니당 ~

답글 달기
comment-user-thumbnail
2023년 4월 9일

오 엄청 정리가 깔끔한데요..? 따라해보면서 익혀야 될 거 같아여

답글 달기
comment-user-thumbnail
2023년 4월 9일

자습서같네요 ㅎㅎ

답글 달기
comment-user-thumbnail
2023년 4월 9일

재밌게 읽었습니다!! 타스랑 비슷한 느낌인듯 아닌듯 하네요ㅋㅋㅋ

답글 달기