[Dart] Dart 문법 정리 (1) 변수

다트 문법 정리 (1) 변수

본 글은 내가 보려고 정리한 글이다. 다트를 처음 배우는데, 플러터 개발할 때마다 다트 문법 찾아보기 힘들어서 여기에 한 번에 정리하려 한다.
다트를 가장 쉽게 설명하는 튜토리얼, 그리고 이펙티브 다트 문서까지 제공하는 곳이 바로 다트 공식 문서이다. 이 중 Dart Tour의 내용을 요약하는 중이다.

그 첫 번째가 다트의 변수 관련 문법이다. 다트는 타입 언어이며, 변수마다 타입을 지정해줘야 한다. 또한 기본적으로 null safety가 적용되어 있어서, null을 사용하려면 타입 키워드 뒤에 ?을 붙여주어야 한다. 또한 C++의 템플릿과 마찬가지로 다트에선 제네릭을 제공한다.
또한 다트에서는 C++의 auto와 마찬가지로 타입 추론을 지원한다. 그게 바로 var인데, var 변수는 기본적으로 컴파일러가 알아서 타입을 추론해준다.

다트 기본 변수 타입

  1. num

intdouble 형 변수를 모두 나타낸다.

num number1 = 10; 
num number2 = 10.0;
  1. int

integer 32비트 정수형이다.

int number = 10
  1. double

double 64비트 실수형이다.

double number = 10.0;
  1. String

문자열을 나타낸다. C++의 std::string과 같은 역할이다. 다트에선 String, List 등과 같은 컨테이너는 앞 글자가 대문자임에 주의하자.

String str1 = "Hello world";
  1. bool

참(true)와 거짓(false)를 나타내는 논리값이다.

bool flag0 = true; 
bool flag1 = false;
  1. dynamic

어떤 타입이든 받을 수 있다. C++의 std::any와 비슷하다. 또는 파이썬, 자바스크립트와 같은 타입리스 형 언어들과 비슷한 역할이다.위 예시에서 dynamic으로 선언된 a에 대해 어떠한 타입을 대입하는 것도 허용된다. 개인적으로 C++의 문법에 익숙한 나로썬 사용하기 꺼려지는 문법이다.

dynamic a = 1; 
a = 'hello'; 
a = 1.1; a = true;
  1. List

리스트이다. C++의 std::list처럼 더블 링크드 리스트의 그 리스트는 아니고, std::vector와 같이 배열 형태로 구현되어 있다.마찬가지로 앞글자가 대문자임에 주의하자. 한편 다트에서 위와 같이 제네릭을 사용하지 않고 다음과 같이 선언 및 정의할 수도 있다.list1을 보면 var로 선언한 것을 알 수 있다. 이때 list1, list2의 타입은 List<int> 형이다.
한편 list2를 보면, ...이란 연산자를 사용한 것을 볼 수 있는데, 이는 Spread Operator라 하며, 한 리스트 안에 또다른 리스트를 삽입할 때 사용할 수 있다.
List에는 length 등의 편리한 메소드 함수들을 추가 제공한다.

var list1 = [1, 2, 3]; 
var list2 = [0, ...list1]; 
print(list2); // [0, 1, 2, 3]
List<String> list_str = ['a', 'b', 'c']; 
List<int> list_int = [1, 2, 3]; List<num> list_num = [1, 2, 3, 3.14]; 
List<dynamic> list_dynamic = [1, 2, 3.14, 'a', 'b', true];
  1. Map

C++의 std::unordered_map과 같다. 따라서 key들이 정렬되지 않음을 주의하자. 대신 해시맵과 마찬가지로 O(1)의 시간 안에 삽입 삭제가 이루어진다.

var gifts = { // Key: Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' };
var nobleGases = {  
2: 'helium',  
10: 'neon',  
18: 'argon',  
};

위 코드에서 gifts의 타입은 Map<String, String>이고, nobleGases의 타입은 Map<int, String>이다.

또는 다음과 같이 Map constructor를 이용하기도 한다.

var gifts = Map<String, String>();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map<int, String>();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
  1. Set

집합이다. C++의 std::unordered_set과 같다.

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Set<int> numbers = { 1, 3, 5, 7 };

halogens의 타입은 Set<String>이다.

다음과 같이 Set constructor를 이용할 수도 있다.

var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

Set에는 {}, Map에는 [] 이 사용됨을 기억하자.

다트 변수 키워드

const, final

const는 컴파일 상수로, C++의 constexpr의 역할이다.
final은 상수화로, C++의 const와 같다.

const, final은 사용할 수 있는 곳에 모두 사용하는 것이 좋다.

Late variables

다트는 기본적으로 null safe 언어이기 때문에, 처음 변수를 선언하면 무조건 초기화를 해주어야 한다. 하지만 초기화가 선언 이후에 돼야 하는 경우, 우리는 late 키워드를 붙여서 이것이 후에 값을 가질 것이다라고 컴파일러에게 알려줄 수 있다.

late String description;

void main() {
  description = 'Feijoada!';
  print(description);
}

late를 사용하는 시나리오는 두 가지 경우가 있다:

  • 선언 이후에 초기화되는 non-nullable 한 변수를 만들 때
  • 뒤늦게 초기화되는 변수

? 키워드

다트는 기본적으로 null safe한 언어이기에 그냥 변수를 선언하면 모두 non-nullable하다. 그러나 변수의 타입 뒤에 ?을 붙여준다면 nullable한 변수를 만들 수 있다.

  int? lineCount;
  print(lineCount); // null
  assert(lineCount == null);

lineCount는 nullable한 변수로써 null값을 가질 수 있다.