[Dart 기초] 컴파일 방법, 기본 문법, 변수 선언하는 법

지은·2023년 10월 10일
0

Dart/Flutter

목록 보기
1/5
post-thumbnail

왜 Dart 가 특별한가?

Dart의 컴파일러

Dart는 Dart Web과 Dart Native, 2개의 컴파일러를 가지고 있다.

  1. Dart Web : Dart로 쓴 코드를 JavaScript로 변환해주는 컴파일러
  2. Dart Native : Dart로 쓴 코드를 여러 CPU의 아키텍쳐에 맞게 변환해주는 컴파일러
    • ARM 32
    • ARM 64 (대부분의 모바일 폰이 사용하는 CPU)
    • x86_64 (데스크탑 CPU)
      ➡️ iOS, Android, Windows, Linux, Mac에서 모두 작동할 수 있도록 컴파일해준다.

Dart가 컴파일하는 방법

JIT(Just-in-time)

개발할 때 JIT 컴파일러 사용

  • 핫 리로드가 가능해 코드의 변경 사항을 즉시 확인할 수 있다.
  • DevTools, 다양한 디버깅 툴을 제공한다.
  • 하지만 JIT로 컴파일된 코드는 VM에서 실행되기 때문에 AOT로 컴파일된 코드보다 느릴 수 있다.

AOT(Ahead-of-time)

프로덕션으로 배포할 때 AOT 컴파일러 사용

  • 애플리케이션을 실제 사용자에게 배포할 때는 AOT 컴파일러를 사용하여 성능을 최적화한다.
  • 최적화되었기 때문에 성능이 더 좋고 빠르다.
  • Windows, macOS, Andriod, iOS 등 다양한 플랫폼에 대한 바이너리를 생성할 수 있다.

바이너리(Binary)

: 컴퓨터(CPU)가 이해하고 실행할 수 있는 기계어 코드로 된 파일

하나의 Dart 소스 코드로부터 Windows 운영체제에서 실행할 수 있는 Windows용 바이너리와, macOS에서 실행할 수 있는 macOS용 바이너리를 생성할 수 있다는 뜻이다.
이렇게 하면 하나의 코드로, 동일한 애플리케이션을 여러 플랫폼에서 실행할 수 있게 된다.


Dart 문법

이제 syntax부터 하나씩 뽀개보자..

기초 Syntax

main() 함수

  • main 함수는 모든 Dart 프로그램의 엔트리 포인트로, 프로그램이 시작되는 지점이다.
  • main 함수 내부에 작성한 코드가 프로그램 실행 시 호출되므로, 모든 Dart 프로그램은 main 함수를 포함해야 하며 그 안에 코드를 작성해야 한다.
void main() {
  // main 함수 안에 코드 작성
}

세미콜론 ;

  • Dart에서 세미콜론(;)은 문장의 종료를 나타내는데 중요하다.
    따라서 세미콜론을 빼먹으면 문법 오류가 발생하므로 주의해야 한다.
  • code formatter도 세미콜론을 자동으로 추가해주지 않기 때문에 직접 작성해야 한다.
void main() {
  print('Hello World');
}

변수 선언 방법

Dart에서 변수를 선언하는 법은 크게 2가지가 있다.

1. var 키워드로 선언

  • 타입을 명시적으로 작성하지 않아도 된다. Dart가 초기값으로 타입을 추론한다.
  • 한 번 변수가 선언되면 해당 변수의 타입을 변경할 수 없다.
    • 만약, 다른 타입으로 업데이트려고 할 시 오류가 발생한다.
    • 따라서 변수를 수정할 때는 같은 타입의 값을 할당해줘야 한다.
void main() {
  var name = '지은';
  name = '지지'; // 가능
  name = 1; // 에러 발생
}

2. 타입을 지정하여 선언

  • 변수의 타입을 명시적으로 지정할 수 있다.
  • 마찬가지로 해당 타입의 값만 저장할 수 있으며, 다른 타입으로 업데이트하려고 할 시 오류가 발생한다.
void main() {
  String name = '지은';
  name = '지지'; // 가능
  name = 1; // 에러 발생
}

그렇다면 어떨 때 var를 사용하고 어떨 때 타입을 지정하여 선언하는가?

  • 관례적으로 함수나 메소드 내부에 지역 변수를 선언할 때는 var 키워드를 사용하고,
  • 클래스나 객체의 멤버 변수나 속성을 선언할 때는 변수의 의도를 명확하게 하기 위해 타입을 지정한다.

만약 내가 어떤 변수에 한 가지 타입의 값이 아니라 여러 가지 타입의 값을 저장하고 싶다면?
dynamic 키워드를 사용하면 된다.

3. dynamic 변수

  • dynamic 키워드를 사용해 여러 가지 타입을 가질 수 있는 변수를 선언할 수 있다.
  • dynamic 키워드로 선언된 변수는 값을 할당할 때마다 타입이 변경된다.
void main() {
  dynamic name;
  name = 1;
  name = true;
  name = '지지';
}

var 키워드를 사용해 변수를 선언하고 초기값을 주지 않으면, 해당 변수는 dynamic 변수가 된다.

void main() {
  var name; // 선언만 하고 값 할당 X
  name = 1;
  name = true;
  name = '지지';
}

is 키워드를 사용해 동적으로 타입을 확인할 수 있다.

void main() {
  dynamic name;

  name = '지지';
  if (name is String) {
    print(name.length); // 문자열 길이 출력: 2
  }
  
  name = 1
  if (name is int) {
    print(name.isEven); // 짝수 여부 출력: false
  }
}

4. Final 변수

: 수정할 수 없는 변수

  • 값을 한 번만 할당할 수 있고, 한 번 값을 할당하면 더 이상 값을 변경할 수 없다.
  • JavaScript에서 const 키워드와 비슷하다.
  • 타입을 명시적으로 지정할 수도 있다.
void main() {
  final name = '지은';
  final String name = '지은'; // 타입 지정 가능
  name = '지지'; // 변수 재할당 불가능
}

5. Late modifier

late modifier를 사용하면 final 변수를 초기값 없이 선언할 수 있게 해준다.

  • late로 선언한 변수는 선언 시점에 값을 할당하지 않아도 되며, 나중에 필요한 시점에서 값을 할당할 수 있다.
void main() {
  late final String name; // 선언
  // ...
  name = '지은'; // 할당
}
  • 값을 할당하기 전에 참조하면 에러가 발생한다.
void main() {
  late final String name;
  print(name); // 에러 발생
}

6. Constant 변수

상수(const) 변수는 컴파일 단계에서 평가되므로 변수의 값을 선언 시점에서 알아야 한다.

  • const 변수는 런타임시 값이 변경되지 않는 것이 보장된다.
  • 상수 변수는 함수 호출 등 런타임에 결정되는 값으로 초기화할 수 없다.
void main() {
  const API = '123123'; // O
  const API = fetchApi(); // X
}

Nullable 변수와 Null Safety

  • Null Safety란 개발자가 null 값을 참조하지 못하도록 하는 기능으로,
    런타임에 null 관련 오류를 방지하고 컴파일 시간에 미리 발견할 수 있도록 도와준다.
  • Dart에서 Nullable 변수를 사용할 때는 변수의 타입 뒤에 물음표 ?를 붙여 해당 변수가 null 값이 될 수 있음을 나타내야 한다.
void main() {
  String name = '지은';
  name = null; // 불가능
  
  String? dog = '지지';
  dog = null; // 가능
}
  • Nullable 변수를 사용할 때는 변수를 사용하기 전에 반드시 null 여부를 확인해야 한다.
void main() {
  String? dog = '지지';
  dog = null;
  
  print(dog.length); // 불가능 (null에 length 프로퍼티가 없으므로 에러 발생)
  
  if (dog != null) {
    print(dog.length); // 가능
  }
}
  • null 여부를 간편하게 확인하고 싶을 때는 null-aware 연산자 ?.를 사용할 수 있다.
void main() {
  String? dog = '지지';
  dog = null;
  print(dog?.length); // dog가 null이 아니라면 dog의 length를 출력한다. (null이면 null을 반환)
}

Null Safety는 Nullable 변수들을 올바르게 처리하도록 코드를 작성하게 함으로써 런타임 오류를 방지해주고 코드의 안정성을 높여준다.

profile
블로그 이전 -> https://janechun.tistory.com

6개의 댓글

comment-user-thumbnail
2023년 10월 19일

dart 공부하시는 군요 !
final과 null부분에서 저도 오류를 많이 경험했던 기억이.... ㅠㅠㅠ js에서 안하던 부분을 신경써야해서 어렵더라구요...

답글 달기
comment-user-thumbnail
2023년 10월 19일

들어만 봤는데 신기하네영 얇게 훓고 갑니다~

답글 달기
comment-user-thumbnail
2023년 10월 22일

한 코드로 앱도 웹도 할 수 있는건가용? 신기하네욥

답글 달기
comment-user-thumbnail
2023년 10월 22일

오 다트 오랜만이네요 완전 하이브리드라 미래엔 웹 앱 등등 다 얘로만 끝냈으면 좋겠네요,, ㅠ

답글 달기
comment-user-thumbnail
2023년 10월 22일

비슷한데 뭔가 다르네욥 화이팅입니다 ㅎㅎ

답글 달기
comment-user-thumbnail
2023년 10월 22일

구글의 Dart! 2개의 컴파일러를 사용했군요! 간단히 읽을 수 있도록 정리해주셔서 감사합니다!

답글 달기