내장 타입

내장 타입 (Built-in types)

Dart가 특별히 지원하는 타입들이 어떤 것들이고, 각각을 어떻게 다루는지 살펴볼게요. 숫자, 문자열, 불리언부터 runes와 심볼까지 차례로 봐요.

출처: Dart 공식 문서

본문

Dart 언어는 다음 타입들을 특별히 지원해요.

이 지원에는 리터럴(literal)로 객체를 만드는 능력이 포함돼요. 예를 들어 'this is a string'은 문자열 리터럴이고, true는 불리언 리터럴이에요.

Dart의 모든 변수는 클래스의 인스턴스인 객체를 가리키기 때문에, 보통 *생성자(constructor)*로 변수를 초기화할 수 있어요. 일부 내장 타입은 자기만의 생성자를 갖고 있어요. 예를 들어 Map() 생성자로 맵을 만들 수 있죠.

Dart 언어에서 특별한 역할을 하는 타입도 몇 가지 더 있어요.

  • ObjectNull을 제외한 모든 Dart 클래스의 수퍼클래스예요.
  • Enum — 모든 enum의 수퍼클래스예요.
  • FutureStream비동기 프로그래밍에서 사용돼요.
  • Iterablefor-in 루프와 동기 제너레이터 함수에서 사용돼요.
  • Never — 표현식이 평가를 성공적으로 끝낼 수 없다는 것을 나타내요. 항상 예외를 던지는 함수에 가장 자주 쓰여요.
  • dynamic — 정적 검사(static checking)를 끄고 싶다는 것을 나타내요. 보통은 ObjectObject?를 쓰는 게 좋아요.
  • void — 값이 사용되지 않는다는 것을 나타내요. 반환 타입으로 자주 쓰여요.

Object, Object?, Null, Never 클래스는 클래스 계층에서 특별한 역할을 해요. 자세한 내용은 Understanding null safety에서 확인할 수 있어요.

Numbers

Dart의 숫자는 두 종류예요.

  • int플랫폼에 따라 64비트를 넘지 않는 정수 값이에요. 네이티브 플랫폼에서는 -263부터 263 - 1까지의 값을 가질 수 있어요. 웹에서는 정수 값이 JavaScript 숫자(소수부가 없는 64비트 부동소수점 값)로 표현되며 -253부터 253 - 1까지의 값을 가질 수 있어요.
  • double — IEEE 754 표준이 규정한 64비트(배정밀도) 부동소수점 숫자예요.

intdouble은 둘 다 num의 하위 타입이에요. num 타입은 +, -, /, * 같은 기본 연산자를 포함하고, abs(), ceil(), floor() 같은 메서드도 여기서 찾을 수 있어요. (>> 같은 비트 연산자는 int 클래스에 정의돼 있어요.) num과 그 하위 타입이 원하는 걸 제공하지 않는다면, dart:math 라이브러리를 확인해 보면 돼요.

정수(integer)는 소수점이 없는 숫자예요. 정수 리터럴을 정의하는 예시를 볼게요.

var x = 1;
var hex = 0xDEADBEEF;

숫자에 소수점이 있으면 double이에요. double 리터럴을 정의하는 예시를 볼게요.

var y = 1.1;
var exponents = 1.42e5;

변수를 num으로 선언할 수도 있어요. 이렇게 하면 그 변수는 정수 값과 double 값을 모두 가질 수 있어요.

num x = 1; // x can have both int and double values
x += 2.5;

정수 리터럴은 필요할 때 자동으로 double로 변환돼요.

double z = 1; // Equivalent to double z = 1.0.

문자열을 숫자로, 또는 그 반대로 바꾸는 방법을 볼게요.

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

int 타입은 전통적인 비트 시프트(<<, >>, >>>), 보수(~), AND(&), OR(|), XOR(^) 연산자를 지정해요. 이들은 비트 필드에서 플래그를 조작하고 마스킹할 때 유용해요. 예를 들면 다음과 같아요.

assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 | 4) == 7); // 0011 | 0100 == 0111
assert((3 & 4) == 0); // 0011 & 0100 == 0000

더 많은 예시는 bitwise and shift operator 섹션에서 볼 수 있어요.

숫자 리터럴은 컴파일 타임 상수예요. 많은 산술 표현식도 피연산자가 숫자로 평가되는 컴파일 타임 상수라면 컴파일 타임 상수가 돼요.

const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;

자세한 내용은 Numbers in Dart를 참고해요.

하나 이상의 밑줄(_)을 숫자 구분자(digit separator)로 사용해서 긴 숫자 리터럴을 더 읽기 쉽게 만들 수 있어요. 여러 구분자를 쓰면 더 높은 수준의 그룹핑도 가능해요.

var n1 = 1_000_000;
var n2 = 0.000_000_000_01;
var n3 = 0x00_14_22_01_23_45; // MAC address
var n4 = 555_123_4567; // US Phone number
var n5 = 100__000_000__000_000; // one hundred million million!

Strings

Dart 문자열(String 객체)은 UTF-16 코드 유닛의 시퀀스를 담아요. 문자열을 만들 때는 작은따옴표나 큰따옴표를 쓰면 돼요.

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

${표현식}를 써서 문자열 안에 표현식의 값을 넣을 수 있어요. 표현식이 식별자(identifier)라면 {}를 생략할 수 있어요. 객체에 해당하는 문자열을 얻기 위해 Dart는 그 객체의 toString() 메서드를 호출해요.

var s = 'string interpolation';

assert(
  'Dart has $s, which is very handy.' ==
      'Dart has string interpolation, '
          'which is very handy.',
);
assert(
  'That deserves all caps. '
          '${s.toUpperCase()} is very handy!' ==
      'That deserves all caps. '
          'STRING INTERPOLATION is very handy!',
);

문자열을 인접한 문자열 리터럴로 이어 붙이거나 + 연산자로 연결(concatenate)할 수 있어요.

var s1 =
    'String '
    'concatenation'
    " works even over line breaks.";
assert(
  s1 ==
      'String concatenation works even over '
          'line breaks.',
);

var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');

여러 줄 문자열을 만들려면 작은따옴표나 큰따옴표로 된 삼중 따옴표를 쓰면 돼요.

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a
multi-line string.""";

r을 앞에 붙여 "raw" 문자열을 만들 수 있어요.

var s = r'In a raw string, not even \n gets special treatment.';

문자열에서 유니코드 문자를 표현하는 방법에 대한 자세한 내용은 Runes and grapheme clusters를 참고해요.

문자열 리터럴은, 보간된 표현식이 전부 null이나 숫자·문자열·불리언 값으로 평가되는 컴파일 타임 상수인 한, 컴파일 타임 상수예요.

// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

문자열 사용에 대한 더 자세한 내용은 Strings and regular expressions에서 확인할 수 있어요.

Booleans

불리언 값을 나타내기 위해 Dart에는 bool이라는 타입이 있어요. 타입이 bool인 객체는 두 개뿐이에요. 불리언 리터럴 truefalse이고, 둘 다 컴파일 타임 상수예요.

Dart의 타입 안전성 덕분에 if (*비불리언 값*)이나 assert (*비불리언 값*) 같은 코드는 쓸 수 없어요. 대신 값을 명시적으로 검사해야 해요. 이렇게요.

// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);

// Check for zero.
var hitPoints = 0;
assert(hitPoints == 0);

// Check for null.
var unicorn = null;
assert(unicorn == null);

// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

Runes와 그래핌 클러스터 (Runes and grapheme clusters)

Dart에서 runes는 문자열의 유니코드 코드 포인트를 드러내요. 사용자가 인식하는 문자, 즉 유니코드 (확장) 그래핌 클러스터를 보거나 조작하려면 characters 패키지를 쓰면 돼요.

유니코드는 세계의 모든 문자 체계에서 쓰이는 각 글자, 숫자, 기호에 고유한 숫자 값을 정의해요. Dart 문자열은 UTF-16 코드 유닛의 시퀀스이기 때문에, 문자열 안에서 유니코드 코드 포인트를 표현하려면 특별한 문법이 필요해요. 유니코드 코드 포인트를 표현하는 일반적인 방법은 \uXXXX인데, 여기서 XXXX는 4자리 16진수 값이에요. 예를 들어 하트 문자(♥)는 \u2665예요. 4자리보다 많거나 적은 16진수를 지정하려면 값을 중괄호로 감싸면 돼요. 예를 들어 웃는 이모지(😆)는 \u{1f606}이에요.

개별 유니코드 문자를 읽거나 써야 한다면, characters 패키지가 String에 정의한 characters 게터를 쓰면 돼요. 반환되는 Characters 객체는 그래핌 클러스터 시퀀스로 본 문자열이에요. characters API 사용 예시를 볼게요.

import 'package:characters/characters.dart';

void main() {
  var hi = 'Hi 🇩🇰';
  print(hi);
  print('The end of the string: ${hi.substring(hi.length - 1)}');
  print('The last character: ${hi.characters.last}');
}

환경에 따라 출력은 대략 이렇게 나와요.

$ dart run bin/main.dart
Hi 🇩🇰
The end of the string: ???
The last character: 🇩🇰

characters 패키지로 문자열을 조작하는 자세한 방법은 그 패키지의 exampleAPI reference에서 확인할 수 있어요.

Symbols

Symbol 객체는 Dart 프로그램에 선언된 연산자나 식별자를 나타내요. 심볼을 쓸 일은 거의 없을지 몰라도, 이름으로 식별자를 참조하는 API에는 아주 유용해요. 축소(minification)가 식별자 이름은 바꿔도 식별자 심볼은 바꾸지 않기 때문이에요.

식별자에 대한 심볼을 얻으려면 심볼 리터럴을 쓰면 되는데, 이는 # 뒤에 식별자를 붙인 것뿐이에요.

#radix
#bar

심볼 리터럴은 컴파일 타임 상수예요.

더 알아보기 (Learn more)