? 및 ! 연산자
Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 25번째.
nullable 타입으로 작업할 때, Dart는 값에 안전하게 접근하기 위한 두 가지 필수 연산자를 제공합니다. null-aware access 연산자 ?.와 null assertion 연산자 !는 잠재적인 null 값을 처리하는 방법을 제어할 수 있게 해줍니다.
?. 연산자는 null이 될 수 있는(nullable) 값의 속성이나 메서드에 안전하게 접근합니다. 값이 null인 경우, 오류가 발생하여 중단되는 대신 전체 표현식은 null을 반환합니다:
String? name = 'Alice';
print(name?.length); // 5
name = null;
print(name?.length); // null (오류 발생 안 함!)! 연산자는 Dart에게 "이 값은 null이 아님을 확신합니다"라고 알려줍니다. 이 연산자는 null 허용(nullable) 타입을 null 비허용(non-nullable) 타입으로 변환하지만, 실제로 값이 null인 경우 에러를 발생시킵니다:
String? maybeName = 'Bob';
String definite = maybeName!; // 확인 - null이 아님을 단언합니다
print(definite.length); // 3
String? empty = null;
// String crash = empty!; // 런타임 에러! 값이 null이었습니다null 값을 유연하게 처리하고 싶을 때 ?.을 사용하세요. 값이 존재한다는 것이 확실할 때만 !를 사용하세요. 예를 들어 if 문으로 확인한 후이거나 로직상 값이 보장된다는 것을 알 때입니다. !를 남용하면 null 안정성의 목적이 퇴색되고 런타임 충돌이 발생할 수 있습니다.
챌린지
쉬움?. 및 ! 연산자를 사용하여 null 허용 값을 안전하게 다루는 방법을 보여주는 제품 인벤토리 시스템을 구축해 보겠습니다.
코드를 정리하기 위해 두 개의 파일을 생성합니다:
product.dart: 인벤토리의 항목을 나타내는Product클래스를 정의합니다. 일부 제품은 완전한 정보를 가지고 있지만, 다른 제품은 아직 카탈로그에 등록 중입니다. 클래스에는 다음이 포함되어야 합니다:- null 허용되지 않는
String name- 모든 제품은 이름을 가져야 합니다. - null 허용되지 않는
double price- 모든 제품은 가격을 가져야 합니다. - null 허용되는
String? description- 일부 제품은 아직 설명이 없습니다. - null 허용되는
String? category- 일부 제품은 아직 카테고리가 지정되지 않았습니다. name과price를 필수 매개변수로 받는 생성자?.를 사용하여 설명의 길이를 반환하거나, 설명이 없으면null을 반환하는getDescriptionLength()메서드!를 사용하여 카테고리를 대문자로 반환하는getCategoryUppercase()메서드 - 이 메서드는 카테고리가 이미 설정되었다고 가정합니다.- 제품 정보를 출력하는
displayProduct()메서드. 설명이 null일 때는"No description"을, 카테고리가 null일 때는"Uncategorized"를 표시합니다.
- null 허용되지 않는
main.dart: 제품 클래스를 임포트하고 두 연산자를 모두 시연합니다:- 이름이
'Laptop'이고 가격이999.99인 제품을 생성한 다음, 설명을'High-performance computing device'로, 카테고리를'Electronics'로 설정합니다. - 이름이
'Mystery Item'이고 가격이49.99인 제품을 생성합니다 (설명과 카테고리는 null로 둡니다). - Laptop의 경우:
displayProduct()를 호출하고,getDescriptionLength()를 사용하여Description length: [length]를 출력하며,getCategoryUppercase()를 사용하여Category: [uppercase]를 출력합니다. - Mystery Item의 경우:
displayProduct()를 호출하고,getDescriptionLength()를 사용하여Description length: [length]를 출력합니다 (이때null이 표시됩니다).
- 이름이
displayProduct() 메서드는 다음 형식으로 출력해야 합니다:
Product: [name] - $[price]
Description: [description or "No description"]
Category: [category or "Uncategorized"]예상 출력 결과:
Product: Laptop - $999.99
Description: High-performance computing device
Category: Electronics
Description length: 32
Category: ELECTRONICS
Product: Mystery Item - $49.99
Description: No description
Category: Uncategorized
Description length: null치트 시트
null-aware access 연산자 ?.는 nullable 값의 속성이나 메서드에 안전하게 접근합니다. 값이 null인 경우, 에러를 발생시키는 대신 null을 반환합니다:
String? name = 'Alice';
print(name?.length); // 5
name = null;
print(name?.length); // null (충돌 없음!)null 단언 연산자 !는 nullable 타입을 non-nullable 타입으로 변환합니다. 값이 null이 아님이 확실할 때만 사용하세요. 실제 값이 null인 경우 런타임 에러가 발생하기 때문입니다:
String? maybeName = 'Bob';
String definite = maybeName!; // OK - null이 아님을 단언함
print(definite.length); // 3
String? empty = null;
// String crash = empty!; // 런타임 에러!유연한 null 처리를 위해서는 ?.를 사용하고, 값이 존재한다는 것이 절대적으로 확실할 때만 !를 사용하세요.
직접 해보기
import 'product.dart';
void main() {
// TODO: 가격이 999.99인 'Laptop'이라는 이름의 제품을 생성하세요
// 그런 다음 설명을 'High-performance computing device'로 설정하세요
// 그리고 카테고리를 'Electronics'로 설정하세요
// TODO: 가격이 49.99인 'Mystery Item'이라는 이름의 제품을 생성하세요
// 설명과 카테고리는 null로 남겨두세요
// TODO: Laptop 제품에 대해 다음을 수행하세요:
// - displayProduct()를 호출하세요
// - getDescriptionLength()를 사용하여 "Description length: [length]"를 출력하세요
// - getCategoryUppercase()를 사용하여 "Category: [uppercase]"를 출력하세요
// TODO: Mystery Item 제품에 대해 다음을 수행하세요:
// - displayProduct()를 호출하세요
// - getDescriptionLength()를 사용하여 "Description length: [length]"를 출력하세요
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.