Null safety - ?, !, ??, ?. ์ธ์ ๋ญ ์ฐ๋
์ง๋ ๊ธ์์ late final์ ๋ค๋ฃจ๋ฉด์ "๊ฐ์ด ์๋ ์ํ"๋ฅผ ๋ค๋ค๋๋ฐ, ์ฌ์ค Dart์๋ ๊ทธ ์ด์ ์ ๋ ๊ทผ๋ณธ์ ์ธ ๊ท์น์ด ํ๋ ๊น๋ ค์๋ค. ํ์
์ ์ ์ธํ ๋, ๊ทธ ๊ฐ์ด null์ด ๋ ์ ์๋์ง ์๋์ง๋ฅผ ๋ฏธ๋ฆฌ ์ ํด์ผ ํ๋ค. ์ด๊ฒ Null safety๋ค.
์ด๋ฐ ์ฝ๋๋ฅผ ์ง๋ณธ๋ค๊ณ ํด๋ณด์. ์ฌ์ฉ์๊ฐ ๋๋ค์์ ์์ง ์ ์ ํ์ ์๋ ์์ผ๋, null์ด ๋ค์ด์ฌ ์ ์๊ฒ ๋ง๋ค์๋ค.
class User {
String nickname;
User(this.nickname);
}
void greet(User user) {
print('์๋
, ${user.nickname}');
}
void main() {
final user = User(null); // ์ฌ๊ธฐ์ ์๋ฌ๋จ
}User(null) ์ด ์ค์์ ๋ฐ๋ก ์๋ฌ๊ฐ ๋๋ค. The argument type 'Null' can't be assigned to the parameter type 'String'. ์ด? ๋๋ค์์ด ์์ ์๋ ์๋ ๊ฑด๋ฐ, ์ null์ ๋ชป ๋ฃ๊ฒ ๋ง์ง?
์์ธ: String์ ๊ธฐ๋ณธ์ ์ผ๋ก "๋ฌด์กฐ๊ฑด ๊ฐ์ด ์๋ค"๋ ํ์
์ด๋ค
Dart๋ ํ์
์ ์ ์ธํ๋ฉด, ๊ธฐ๋ณธ์ ์ผ๋ก **"์ด ์๋ฆฌ์ null์ด ์ ๋ ์ฌ ์ ์๋ค"**๊ณ ๋ชป๋ฐ์๋ฒ๋ฆฐ๋ค. String nickname;์ด๋ผ๊ณ ๋ง ์ฐ๋ฉด ์ปดํ์ผ๋ฌ๋ "์ด nickname์ ํญ์ ์ง์ง ๋ฌธ์์ด์ด ๋ค์ด์๋ค"๊ณ 100% ๋ฏฟ๊ณ ์ฝ๋๋ฅผ ๋ง๋ ๋ค. ๊ทธ๋์ ์ ์ด์ null์ ๋ฃ์ผ๋ ค๋ ์๋ ์์ฒด๋ฅผ ์ปดํ์ผ ์์ ์ ๋ง์๋ฒ๋ฆฌ๋ ๊ฑฐ๋ค.
์ด๊ฑด Kotlin์ด๋ ๋๊ฐ์ ๋ฐฉ์์ด๋ค. Kotlin๋ String์ด๋ผ๊ณ ๋ง ์ฐ๋ฉด null์ ๋ชป ๋ฃ๊ณ , null์ด ๊ฐ๋ฅํ๋ ค๋ฉด String?์ด๋ผ๊ณ ๋ฌผ์ํ๋ฅผ ๋ถ์ฌ์ผ ํ๋ค. Dart๋ ๋๊ฐ์ด ๋ฌผ์ํ๋ฅผ ์ด๋ค.
๊ณ ์น ์ฝ๋: ?๋ฅผ ๋ถ์ฌ์ "null์ผ ์๋ ์๋ค"๊ณ ์ ์ธํ๋ค
class User {
String? nickname; // ?๋ฅผ ๋ถ์ฌ์ null ํ์ฉ
User(this.nickname);
}
void main() {
final user = User(null); // ์ด์ OK
}String?์ "String์ด๊ฑฐ๋, ์๋๋ฉด null"์ด๋ผ๋ ๋ป์ด๋ค. ? ํ๋๋ก "์ด ์๋ฆฌ์ ๊ฐ์ด ์์ ์๋ ์๋ค"๋ ๊ฑธ ํ์
์์ฒด์ ์๊ฒจ๋ฃ๋ ๊ฑฐ๋ค.
๊ทผ๋ฐ ์ด๋ ๊ฒ ํ๋ฉด ๋ ๋ค๋ฅธ ๋ฐ์ ๋งํ๋ค
void greet(User user) {
print('์๋
, ${user.nickname.toUpperCase()}'); // ์ฌ๊ธฐ์ ์๋ฌ๋จ
}The property 'toUpperCase' can't be unconditionally accessed because the receiver can be 'null'. ์๊น๋ null์ ๋ฃ๊ฒ ํด๋ฌ๋ผ๊ณ ?๋ฅผ ๋ถ์๋๋ฐ, ์ด๋ฒ์ ๊ทธ ๊ฐ์ ์ฐ๋ ค๋๊น ๋ ๋ง๋๋ค. ์ ์ด๋ ๊ฒ ๊ณ์ ๋ง๋ ๊ฑธ๊น?
์์ธ: nickname์ด ์ง์ง String์ธ์ง, null์ธ์ง ์ปดํ์ผ๋ฌ๋ ๋ชจ๋ฅธ๋ค
nickname์ ํ์
์ด String?์ด ๋ ์๊ฐ, ์ปดํ์ผ๋ฌ ์
์ฅ์์๋ "์ด ์์ ์ง์ง ๋ฌธ์์ด์ด ๋ค์ด์์ ์๋ ์๊ณ , null์ด ๋ค์ด์์ ์๋ ์๋ค"๋ ๋ ๊ฐ์ง ๊ฐ๋ฅ์ฑ์ ํญ์ ๊ฐ์ด ๋ณธ๋ค. .toUpperCase()๋ ์ง์ง Stringํํ
๋ง ์ธ ์ ์๋ ๊ธฐ๋ฅ์ธ๋ฐ, ํน์ ์ง๊ธ ์ด ๊ฐ์ด null์ด๋ฉด ๊ทธ ์๊ฐ ์ฑ์ด ๊ทธ๋๋ก ์ฃฝ์ด๋ฒ๋ฆฐ๋ค(๋ฐํ์ ์๋ฌ). ์ปดํ์ผ๋ฌ๋ ์ด๋ฐ ์ํํ ์ฝ๋๋ฅผ ์์ ํต๊ณผ์์ผ์ฃผ์ง ์๋๋ค.
์ฆ ?๋ฅผ ๋ถ์ธ ์๊ฐ๋ถํฐ๋, **๊ทธ ๊ฐ์ ์ค์ ๋ก ์ฐ๊ธฐ ์ ์ "null์ด ์๋๋ผ๋ ๊ฑธ ํ์ธํ๋ ์ ์ฐจ"**๋ฅผ ๊ฑฐ์ณ์ผ ํ๋ค. ์ฌ๊ธฐ์๋ถํฐ ?., ??, !๊ฐ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฐฉ์์ "ํ์ธ ์ ์ฐจ"๋ก ๋ฑ์ฅํ๋ค.
?. โ "null์ด๋ฉด ๊ทธ๋ฅ ์๋ฌด๊ฒ๋ ํ์ง ๋ง๋ผ"
void greet(User user) {
print('์๋
, ${user.nickname?.toUpperCase()}');
}
void main() {
final user1 = User('ํ๊ธธ๋');
greet(user1); // ์๋
, ํ๊ธธ๋... ์ด ์๋๋ผ ์๋
, HONGGILDONG
final user2 = User(null);
greet(user2); // ์๋
, null
}nickname?.toUpperCase()๋ "nickname์ด null์ด ์๋๋ฉด .toUpperCase()๋ฅผ ์คํํ๊ณ , null์ด๋ฉด ๊ทธ๋ฅ ์ ์ฒด๋ฅผ null๋ก ์ฒ๋ฆฌํด๋ผ"๋ ๋ป์ด๋ค. ์๋ฌ๋ฅผ ๋ด๋ ๋์ , "๊ฒฐ๊ณผ๊ฐ null์ผ ์๋ ์๋ค"๋ ๊ฑธ ๊ทธ๋๋ก ๋ฐ์๋ค์ด๋ ๋ฐฉ์์ด๋ค. ๊ทธ๋์ user2์ฒ๋ผ nickname์ด ์์ผ๋ฉด "์๋
, null"์ด ๊ทธ๋๋ก ์ฐํ๋ค โ ์๋ฌ๋ ์ ๋์ง๋ง, ์ํ๋ ๊ฒฐ๊ณผ๋ ์๋๋ค.
?? โ "null์ด๋ฉด ๋์ ์ด ๊ฐ์ ์จ๋ผ"
void greet(User user) {
final name = user.nickname ?? '์ด๋ฆ์์';
print('์๋
, $name');
}
void main() {
final user2 = User(null);
greet(user2); // ์๋
, ์ด๋ฆ์์
}user.nickname ?? '์ด๋ฆ์์'์ "nickname์ด null์ด ์๋๋ฉด ๊ทธ ๊ฐ์ ์ฐ๊ณ , null์ด๋ฉด ๋์ '์ด๋ฆ์์'์ ์จ๋ผ"๋ ๋ป์ด๋ค. ?.๊ฐ "null์ด๋ฉด ํฌ๊ธฐ"์๋ค๋ฉด, ??๋ "null์ด๋ฉด ๋์ฒด๊ฐ์ผ๋ก ๋์ด๋ค"๋ ์ฐจ์ด๊ฐ ์๋ค.
! โ "๋ฌด์กฐ๊ฑด null ์๋๋ผ๊ณ ๋ด๊ฐ ๋ณด์ฅํ๋ค"
void greet(User user) {
print('์๋
, ${user.nickname!.toUpperCase()}');
}
void main() {
final user2 = User(null);
greet(user2); // ์ฌ๊ธฐ์ ๋ฐํ์ ์๋ฌ๋จ
}nickname!์ "์ด ๊ฐ์ ๋ด๊ฐ ๋ณด์ฅํ๋๋ฐ ์ ๋ null์ด ์๋๋ค. ์ปดํ์ผ๋ฌ ๋๋ ๊ทธ๋ฅ ๋ฏฟ๊ณ String์ผ๋ก ์ทจ๊ธํด๋ผ"๋ ๋ป์ด๋ค. ์ปดํ์ผ์ ํต๊ณผ๋์ง๋ง, ๋ง์ฝ ์ค์ ๋ก null์ด์๋ค๋ฉด? Null check operator used on a null value.๋ผ๋ ๋ฐํ์ ์๋ฌ๊ฐ ๊ทธ ์๋ฆฌ์์ ๋ฐ๋ก ํฐ์ง๋ค.
!๋ ์
์ค ์ ์ผ ์ํํ๋ค. ์ปดํ์ผ๋ฌ์ ์์ ์ฅ์น๋ฅผ ๊ฐ์ ๋ก ๋๋ ๊ฑฐ๋ผ์, "์ง์ง๋ก null์ด ์๋ ๊ฑฐ๋ผ๋ ํ์ ์ด ์์ ๋๋ง" ์จ์ผ ํ๋ค. ํ์ ์ด ์์ผ๋ฉด ?.๋ ??๋ฅผ ์ฐ๋ ๊ฒ ๋ง๋ค.
๋ท์ ํ ๋ฌธ์ฅ์ฉ์ผ๋ก ์ ๋ฆฌํ๋ฉด
๋ฌธ๋ฒ | ์๋ฏธ | null์ด๋ฉด |
| ์ด ๊ฐ์ null์ผ ์๋ ์๋ค | - |
| null์ด๋ฉด ์ด ๋์์ ๊ฑด๋๋ด๋ค | ๊ฒฐ๊ณผ๊ฐ null์ด ๋จ |
| null์ด๋ฉด ๋์ฒด๊ฐ์ ์ด๋ค | ์ค๋ฅธ์ชฝ ๊ฐ์ผ๋ก ๋์ฒด๋จ |
| ์ ๋ null ์๋๋ผ๊ณ ๋ด๊ฐ ๋ณด์ฅํ๋ค | ๋ฐํ์ ์๋ฌ |
Kotlin์ด๋ ๋น๊ตํ๋ฉด
Kotlin ํด๋ดค์ผ๋ฉด ์ด ๋ท์ด ๋ฏ์ค์ง ์์ ๊ฑฐ๋ค. ๊ธฐํธ๊น์ง ๊ฑฐ์ ๋๊ฐ๋ค.
Dart | Kotlin | ์๋ฏธ |
|
| null ํ์ฉ ํ์ |
|
| ์์ ํธ์ถ (null์ด๋ฉด ๊ฑด๋๋) |
|
| ์๋น์ค ์ฐ์ฐ์ (null์ด๋ฉด ๋์ฒด๊ฐ) |
|
| null ์๋๋ผ๊ณ ๊ฐ์ ๋จ์ธ |
๊ธฐํธ๊ฐ ๊ฑฐ์ 1:1๋ก ๋์๋ผ์, Kotlin์์ ๋์ด์จ ์
์ฅ์ด๋ฉด ๊ฐ๋
๋ณด๋ค "๋๋ํ ๊ฐ์(! vs !!)"๋ง ํท๊ฐ๋ฆฌ์ง ์์ผ๋ฉด ๋๋ค.
์ ๋ฆฌ
- Dart๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ํ์
์ด "null ๋ถ๊ฐ"์ด๊ณ , null์ ํ์ฉํ๋ ค๋ฉด ํ์
๋ค์
?๋ฅผ ๋ถ์ฌ์ผ ํ๋ค String?์ฒ๋ผ null ๊ฐ๋ฅ ํ์ ์ด ๋๋ฉด, ๊ทธ ๊ฐ์ ์ค์ ๋ก ์ฐ๊ธฐ ์ ์ ๋ฐ๋์ "null ํ์ธ ์ ์ฐจ"๋ฅผ ๊ฑฐ์ณ์ผ ์ปดํ์ผ์ด ํต๊ณผ๋๋ค?.์ null์ด๋ฉด ๊ฑด๋๋ฐ๊ณ ,??๋ null์ด๋ฉด ๋์ฒด๊ฐ์ ์ฐ๊ณ ,!๋ null์ด ์๋๋ผ๊ณ ๊ฐ์ ๋ก ์ฐ๊ธฐ๋ ๊ฒ โ ์ํ๋๊ฐ ๋ค๋ฅด๋ค!๋ ์ค์ ๋ก null์ด๋ฉด ๊ทธ ์๋ฆฌ์์ ๋ฐ๋ก ๋ฐํ์ ์๋ฌ๊ฐ ๋๋ฏ๋ก, ํ์ ์์ผ๋ฉด ์ฐ์ง ์๋ ๊ฒ ์์ ํ๋ค- Kotlin์
?,?.,?:,!!์ ๊ธฐํธ๊น์ง ๊ฑฐ์ ๊ทธ๋๋ก ๋์๋๋ค
๋ค์ ๊ธ์์๋ ํจ์์ ํ์ดํ ํจ์(=>), ์ต๋ช
ํจ์๋ฅผ ๋ค๋ค๋ณด๊ฒ ๋ค.
