식과 연산자
식은 값을 만드는 코드입니다. 대입의 오른쪽, 조건, 인수, 반환값, 컬렉션 항목에 사용합니다.
기본 식
섹션 제목: “기본 식”| 식 | 예 | 결과 |
|---|---|---|
| 리터럴 | 42, 1.5, "Kim", 'a', true, null |
어휘 구조 |
| 이름 | count, name |
지역 변수 → 매개변수 → 현재 클래스 필드 순서로 찾음 |
| 필드 접근 | user.name, Config.MAX, this.id |
인스턴스·정적 필드 |
| 메서드 호출 | user.rename("Lee"), total(3), Math.sqrt(9.0) |
반환값 |
| 생성자 호출 | User("Kim"), List<int>() |
새 객체 |
| 인덱스 | names[0], ages["Kim"] |
항목 |
| 괄호 | (a + b) * c |
먼저 계산 |
| 내장 언어 | sql { … }, json { … }, html { … }, css { … } |
내장 언어와 schema |
await |
await future |
문장 |
연산자 우선순위
섹션 제목: “연산자 우선순위”위에서 아래로 갈수록 먼저 계산합니다. 같은 줄의 이항 연산자는 왼쪽부터 계산합니다.
| 순위 | 연산자 | 설명 |
|---|---|---|
| 1 (가장 나중) | 조건 ? 값1 : 값2 |
삼항 |
| 2 | || |
논리 OR |
| 3 | && |
논리 AND |
| 4 | | |
비트 OR / 논리 OR(단락 없음) |
| 5 | ^ |
비트 XOR |
| 6 | & |
비트 AND / 논리 AND(단락 없음) |
| 7 | == != |
같음·다름 |
| 8 | < <= > >= |
크기 비교 |
| 9 | << >> >>> |
시프트 |
| 10 | + - |
덧셈·뺄셈·문자열 연결 |
| 11 | * / % |
곱셈·나눗셈·나머지 |
| 12 | ! ~ - + (앞에 붙음) |
단항 |
| 13 (가장 먼저) | a.b, f(…), a[i] |
멤버·호출·인덱스 |
&, |, ^는 ==보다 나중에 계산합니다. flags & 1 == 0은 flags & (1 == 0)이 되므로 (flags & 1) == 0처럼 괄호를 씁니다.
연산자 타입 규칙
섹션 제목: “연산자 타입 규칙”| 연산자 | 피연산자 | 결과 |
|---|---|---|
+ - * / % |
숫자 두 개 | 더 넓은 숫자 타입(최소 int) |
+ |
한쪽이 string |
string — 다른 쪽은 null이 아닌 어떤 타입이든 가능 |
< <= > >= |
숫자·char |
bool — 문자열 비교는 미지원 |
== != |
서로 대입 가능한 두 타입 | bool |
&& || ! |
bool |
bool |
& | ^ |
bool 두 개 또는 정수 두 개 |
bool 또는 int·long |
<< >> >>> |
정수 | 왼쪽이 long이면 long, 아니면 int |
~ |
정수 | int 또는 long |
단항 - + |
숫자 | 최소 int |
- 정수끼리의
/는 정수 나눗셈입니다.7 / 2는3이며 소수 결과가 필요하면7.0 / 2처럼 실수를 섞습니다. char + char는int입니다. 문자를 이어 붙이려면"" + a + b를 씁니다.- null일 수 있는 값을 그대로 계산하지 않습니다. 지역 변수·매개변수는 null 확인으로 null이 아닌 분기에서 사용합니다. 확인되지 않은
int? + int는Operator '+' cannot be applied to int? and int.오류입니다. ==로 null을 비교할 수 있는 것은 null 허용 타입뿐입니다.string name에name == null을 쓰면Operator '==' cannot be applied to string and null.오류입니다.- 서로 관계없는 타입의 비교는
Operator '==' cannot be applied to Widget and Panel.오류입니다. - 문자열 크기 비교(
"a" < "b")는Operator '<' cannot be applied to string and string.오류입니다.
양수 정수의 7 / 2는 공통으로 3입니다. 음수 피연산자의 나눗셈·나머지, 0으로 나누기, 정수 overflow와 NaN·무한대의 결과는 대상 언어를 따릅니다. Python 정수 나눗셈은 내림, TypeScript는 Math.trunc를 사용하므로 -7 / 2의 결과가 각각 -4, -3입니다. 범위를 벗어난 계산이나 오류 문구가 모든 대상에서 같다고 가정하지 마세요.
문자열 연결
섹션 제목: “문자열 연결”string label = "count: " + count; // count: 3string line = "" + 1 + 2; // "12" — 왼쪽부터 계산string sum = "" + (1 + 2); // "3"왼쪽부터 계산하므로 숫자 덧셈을 먼저 하려면 괄호로 묶습니다. double과 bool을 문자열로 표현하는 방식은 대상 언어를 따릅니다. 예를 들어 Python의 bool은 True·False로 표시됩니다.
삼항 연산자
섹션 제목: “삼항 연산자”string size = count > 10 ? "large" : "small";int level = score > 90 ? 3 : (score > 70 ? 2 : 1);- 조건은
bool이어야 합니다 (Ternary condition must be boolean but got int.). - 두 값의 타입은 같거나 숫자 확대로 합쳐져야 합니다 (
Ternary branches cannot be combined: int and string.). 한쪽이null이면 결과는 null 허용 타입입니다(ready ? name : null은string?).
null 확인
섹션 제목: “null 확인”지역 변수·매개변수는 null 확인으로 값이 있는 분기에서 사용할 수 있습니다. 삼항 연산자는 값이 없을 때 대체값을 고를 때 유용합니다.
string? nickname = null;string shown = nickname != null ? nickname : "guest";string shown2 = nickname == null ? "guest" : nickname;if (nickname != null) { … }의 참인 분기에서 nickname은 string으로 좁혀집니다. null일 때 반환하는 분기 뒤, &&·||의 해당 오른쪽 피연산자도 같은 null 확인 규칙을 따릅니다. 필드·메서드 결과, 재대입하는 변수와 반복 조건에는 적용하지 않습니다. ?? 연산자와 ?. 안전 호출은 미지원입니다. 상세 조건을 확인하세요.
메서드 호출
섹션 제목: “메서드 호출”람다를 인수로 전달하거나 지역 변수에 저장하는 방법은 아래 람다와 캡처를 참고하세요.
user.rename("Lee"); // 인스턴스 메서드string upper = name.toUpperCase();int total = add(1, 2); // 같은 클래스의 메서드Math.sqrt(9.0); // 정적 메서드int length = factory.create().name.length(); // 연결 호출- 같은 클래스의 메서드는 이름만으로 호출합니다. 소문자로 시작하는 이름이어야 합니다.
static메서드에서는this와 인스턴스 메서드를 사용할 수 없습니다 (Cannot use 'this' in static context.).private메서드·필드는 다른 클래스에서 보이지 않습니다 (No matching method for A.f.,Field 'P.secret' is not accessible.).- 인수 규칙은 이름 있는 인수를 참고하세요. 인수 개수가 같은 오버로드가 여러 개 맞으면
Ambiguous method call오류입니다. - 메서드에 타입 인수를 직접 지정하는 호출(
convert<int>(x))은 미지원입니다.
string 메서드
섹션 제목: “string 메서드”| 메서드 | 결과 |
|---|---|
length() |
int |
isEmpty(), isNotEmpty(), isBlank() |
bool |
contains(s), startsWith(s), endsWith(s) |
bool |
indexOf(s), lastIndexOf(s) |
int |
charAt(i) |
한 글자를 담은 string |
substring(start), substring(start, end) |
string |
toLowerCase(), toUpperCase(), trim() |
string |
replace(from, to) |
string |
split(separator) |
List<string> |
List·Set·Map의 메서드는 List, Set, Map과 Standard 라이브러리에 있습니다.
생성자 호출
섹션 제목: “생성자 호출”User user = User("Kim", 30);User named = User(name: "Lee", age: 25);List<string> empty = List<string>();Map<string, int> counts = Map<string, int>();Pair<string, int> pair = Pair<string, int>("a", 1);- 형태는
타입이름(인수...)이며 타입 이름은 대문자로 시작합니다. 제네릭 타입은 타입 인수를 함께 씁니다. new User(...)는Legacy constructor keyword is not supported. Use TypeName(...).오류입니다.- 맞는 생성자가 없거나 생성자가
public이 아니면No matching constructor for User at variable 'user'.오류입니다. - 생성자 호출만 있는 문장(
Logger("start");)도 허용합니다.
컬렉션 리터럴
섹션 제목: “컬렉션 리터럴”| 리터럴 | 타입 | 예 |
|---|---|---|
[a, b, …] |
List<T> |
[1, 2, 3] |
{a, b, …} |
Set<T> |
{"red", "blue"} |
{k: v, …} |
Map<K, V> |
{"Kim": 30, "Lee": 25} |
List<int> numbers = [1, 2, 3];List<long> wide = [1, 2L]; // 숫자는 넓은 타입으로 합쳐짐Set<string> colors = {"red", "blue"};Map<string, int> ages = {"Kim": 30};Map<string, string?> notes = {"a": null, "b": "memo"};List<int> pending = []; // 빈 리터럴은 타입을 명시- 항목 타입은 하나로 합쳐져야 합니다.
["a", 1]처럼 섞으면 타입을 정할 수 없습니다. - 끝 쉼표(
[1, 2,])와 빈 항목은 허용하지 않습니다. - 빈
[],{}는 대상 타입을 알 수 있을 때만 사용합니다.var ys = [];는Cannot infer type for variable 'ys' from initializer '[]'.오류입니다. - 맵의 키는 식입니다.
{name: 1}의name은 문자열"name"이 아니라 변수name입니다. 문자열 키에는 따옴표를 씁니다. - 대입 대상의 항목 타입과 맞아야 합니다:
List<int> ids = ["a"];는Cannot assign List<string> to List<int> variable 'ids'.오류입니다.
인덱스 접근
섹션 제목: “인덱스 접근”string first = names[0];int age = ages["Kim"];names[0] = "Choi";string key = entries[0].key;List<T>는int인덱스,Map<K, V>는K키를 사용합니다. 다른 타입은Type 'X' does not support index access.오류입니다.- 인덱스는 0부터 시작하며 마지막 인덱스는
size() - 1입니다. - 문자열의 문자는
text[0]이 아니라text.charAt(0)으로 읽습니다.
this와 super
섹션 제목: “this와 super”| 식 | 의미 | 제한 |
|---|---|---|
this |
현재 객체 | static 메서드에서 사용 불가 |
this.name |
현재 객체의 필드 | 상속받은 필드도 this.로 접근 |
super.method() |
부모 클래스의 메서드 호출 | 부모 클래스가 있을 때만 (Cannot use 'super' in this context.) |
지원하지 않는 식
섹션 제목: “지원하지 않는 식”| 식 | 대체 방법 |
|---|---|
new T() |
T() |
(int) value, value as int |
축소는 toInt()·toLong(), 확대는 toLong()·toDouble() 변환 메서드 |
x is T, x instanceof T |
인터페이스 메서드로 동작을 나누기 |
a ?? b, a?.b |
삼항 연산자 null 확인 |
function(x) { … } 같은 다른 언어의 익명 함수 |
단일 메서드 인터페이스를 대상으로 하는 x => … 람다 |
i++, x += 1 |
i = i + 1, x = x + 1 |
$"{x}", `${x}` |
"" + x |
1e5, .5 |
100000.0, 0.5 |
람다와 캡처
섹션 제목: “람다와 캡처”함수 타입은 (인수 타입들) -> 결과 타입입니다. (int) -> int twice = x => x * 2;처럼 선언하고 twice(3)으로 호출합니다. 인수는 0·1·2개이며 결과에는 void도 사용할 수 있습니다. 중첩 함수 타입 (int) -> (int) -> int도 표현할 수 있습니다.
(int) -> int twice = x => x * 2;(string) -> void show = text => { print(text); };int value = twice(3);show("value=" + value);매개변수는 x, (), (left, right), (int left, int right) 형태이며 타입을 적을 때는 전부 적습니다. 본문은 식 또는 { return ...; } 블록입니다. print는 문장이므로 람다에서는 블록으로 감쌉니다.
람다를 둘 수 있는 위치는 메서드·생성자 인수, 타입을 명시한 지역 변수 초기값, 반환값입니다. var, 필드 초기값, 나중 대입과 연산자 피연산자에는 람다를 직접 둘 수 없습니다. 캡처한 지역 변수·매개변수는 다시 대입할 수 없으며 this의 필드는 변경할 수 있습니다. 람다 매개변수는 바깥 지역 변수 이름을 가릴 수 없습니다.
Predicate<T>는 (T) -> bool, Comparator<T>는 (T,T) -> int의 별칭입니다. 메서드가 하나인 사용자 인터페이스도 람다를 받을 수 있으며 그때는 선언한 메서드 이름으로 호출합니다. Function0/1/2는 내부 표현이므로 소스에서는 화살표 형태를 사용합니다. 사용자 정의 제네릭 메서드는 지원하지 않습니다.
컬렉션의 함수형 연산, Async의 완료 대기, 참조 소스를 함께 읽으세요.