Variables
Keyword | Description |
int | 정수형 |
double | 실수형 |
String | text |
bool | true OR false |
var | 모든 type 저장 가능 BUT 초기화 후 type 변경 불가 |
dynamic | 모든 type 저장 가능 AND 초기화 후 type 변경 가능 |
var VS. dynamic
var는 한 번 type이 선언되면 변경 불가하다
var name = 'Hyoeun';
print(name); // Hyoeun
name = 24; // ERROR
dynamic은 type이 결정된 후에도 type을 변경할 수 있다
dynamic age = 24;
print(age); // 24
age = '나이';
print(age); // 나이
Dart는 정적 타입 언어이므로 dynamic을 최대한 사용하지 않는 것이 좋다
아무래도 dynamic을 사용하면 코드를 읽을 때 헷갈리지 않을까 싶다!
var로 변수에 값을 할당하면 type을 auto casting한다
var a = 1; // 자동으로 int type으로 인식
var list = null; // var는 ?를 붙이지 않아도 기본적으로 nullable하다
var list2 = [0, ...?list]; // null이면 오류가 나지 않고 [0]을 출력한다
var listA = [2];
var listB = [...?listA, 22]; // ERROR: listA가 null이 아니기에 발생한 오류
초기화와 선언
초기화 = 변수에 처음으로 값을 할당하는 것
선언과 동시에 초기화하는 것이 좋다
void main() {
int num; // 선언
num = 22; // 초기화
String name = 'Hyoeun'; // 선언과 동시에 초기화
}
null safety
Dart의 변수는 기본적으로 non-nullable 변수로 지정되어 있다
null도 하나의 값임을 인지하여야 한다
nullable 변수로 만들기 위해서는 type(자료형) 뒤에 ? 키워드를 붙여 선언하면 된다
int num; // non-nullable type
int? num; // nullable type
! 키워드를 활용하면 강제로 non-nullable하게 만들 수 있다
String? name;
name = stdin.readLineSync()!; // null이 아닌 값을 입력할 것이라 확신한다면 ! 키워드를 활용한다
int? num;
num = 22;
print(num!); // num에 절대로 null 값이 들어가지 않을 것이라 확신한다면 ! 키워드를 활용할 수 있다
! 키워드는 가급적 사용하지 않는 것이 좋다
? 키워드를 넣을지 말지 선언할 때 충분히 고민하는 것이 좋을 듯하다
Default value
Default value = 초기화 값
nullable 변수의 default value는 null이다
int? number; // 초기화 값 = null
non-nullable 변수는 초기화 값이 필수다
따라서 선언과 동시에 초기화하는 것이 일반적이다
- Top-level non-nullable 변수는 선언과 동시에 초기화한다
top-level 변수: code block인 중괄호 { }에 속하지 않는 최상위 영역
top-level 변수는 global 변수와 비슷한 개념이다
String date = '2024년 7월 31일';
- Local non-nullable 변수는 선언과 동시에 초기화 되지 않더라도 변수 사용 전 반드시 초기화해야 한다
void main() {
int year;
int month = stdin.readLineSync()!;
if (1 <= month < 7) {
int year = 2024; // 초기화
print('$year년 상반기입니다.');
} else {
print('$year년 하반가입니다.');
}
}
Late variables
나중에 초기화하기를 원할 경우 사용하는 키워드
개발자가 원할 때 초기화하고자 사용한다
개발자가 보장하는 방식은 개발의 편의성을 위해 존재하는 것이기 때문에 별로 좋지 않다
따라서 late도 사용하지 않는 것이 좋다
final과 const
final과 const는 변수를 고정시킨다 > immutable(변하지 않는) 변수
var처럼 final을 붙이면 auto casting되어 자동으로 type이 결정된다
final name = 'Hyoeun' // auto casting되어 자동으로 String type으로 인식
final int number = 1; // 가급적이면 연습을 위해 type 작성할 것
number = 2; // ERROR: 재할당 불가
const int age = 24;
age = 22; // ERROR: 재할당 불가
final과 const의 차이
final: 런타임에 초기화되는 것을 허락한다
const: 컴파일타임에만 초기화될 수 있다
따라서 const는 final보다 조건이 좁기 때문에 더 빠르게 동작한다
영역이 좁을수록 속도가 더 빨라지므로 가능성을 줄여서 코딩하는 것이 좋다
console input
사용자로부터 입력을 받을 때 = stdin 활용
줄 바꿈 없이 출력할 때 = stdout 활용
stdin과 stdout은 dart:io package에 포함된 기능
따라서
import ‘dart:io’;
를 상단에 작성해 주어야 한다readLineSync()
: 입력을 받을 때까지 프로그램 실행을 멈추는 동기 입력사용자가 아무것도 입력하지 않은 채 Enter를 누르면 null을 반환할 수 있으므로
readLineSync()!
처리한다Operators
산술연산자
연산자 | 의미 | 비고 |
+ | 더하기 | ㅤ |
- | 빼기 | ㅤ |
* | 곱하기 | ㅤ |
/ | 나누기(몫) | 실수형(double)로 변환 |
~/ | 나누기(몫) | 정수형(int)로 변환 |
% | 나누기(나머지) | 정수형(int)로 변환 |
증감연산자
증감하는 타이밍이 연산자를 앞에 배치하느냐 뒤에 배치하느냐에 따라 다르다
- 전위증가
++a
int a = 1;
b = ++a; // a 값을 먼저 2로 증가 ⭢ b에 할당 즉 a = 2, b = 2
- 후위증가
a++
int a = 1;
b = a++; // a 값을 b에 할당 ⭢ a 값 증가 즉 a = 2, b = 1
- 전위감소
--a
int a = 1;
b = --a; // a 값을 먼저 0으로 감소 ⭢ b에 할당 즉 a = 0, b = 0
- 후위감소
a--
int a = 1;
b = a--; // a 값을 b에 할당 ⭢ a 값 감소 즉 a = 0, b = 1
논리연산자
Operators | Description |
&& | AND |
|| | OR |
! | NOT |
Collections
collection = 여러 개의 값을 그룹화하는 것 즉 데이터를 모아두는 것
ㅤ | 순서 | 중복 가능 여부 |
List | O | O |
Map | X | Key는 불가, Value는 가능 |
Set | X | X |
Set은 List와 Map으로 구현 가능하기에 보통은 List와 Map을 많이 사용한다
List
순서 O / 중복값 허용 O
대괄호로 선언
String과 같이 사이즈 제한이 없다
index를 통해 value에 접근할 수 있다
List에 type을 지정하려면?
List<String>
type을 따로 지정하지 않으면 dynamic으로 지정된다
generic type = 타입 제한 및 타입 명시
List 안에 List, Map을 중첩해서 넣을 수 있다 > nested list
List 자료를 합치려면 + 연산자 활용할 것
void main(List<String> arguments) {
List firstMembers = ['Kim', 'Lee', 'Park'];
List secondMembers = ['Jung', 'Shin'];
print(firstMembers + secondMembers); // ['Kim', 'Lee', 'Park', 'Jung', 'Shin']
}
List 자료를 보통 item이라 부르지만 원래는 element가 맞다
List의 Method > 수없이 많지만 기본적인 것만 작성
testList.length // 리스트가 가진 아이템 개수
testList.contains(123) // 123이라는 argument가 있는지 확인
List<int> randomNum = [6, 5, 10, 52, 98];
randomNum.sort(); // 오름차순으로 정렬
print(randomNum); // [5, 6, 10, 52, 98]
spread operator(…): List 확장
List<int> number1 = [1, 2, 3, 4];
List<int> number2 = [5, 6, 7];
print([1, 2, 3, 4, ...numbers2]; // [1, 2, 3, 4, 5, 6, 7]
print([...numbers1, ...numbers2]); // [1, 2, 3, 4, 5, 6, 7]
Map
순서 X / Key는 중복 허용 X, Value는 중복 허용 O
중괄호로 선언
key와 value 모두 dynamic으로 동작한다
따라서 list, map, object 전부 들어갈 수 있다
generic type으로 지정하려면
Map<String, dynamic>
형식으로 제한할 수 있다다만 key와 value 중 하나만 타입 제한을 할 수는 없다
key는 거의 String을 사용한다
아무래도 key는 데이터의 의미를 설명하는 내용이 들어가니까 String을 많이 사용할 것 같다 Value는 실습을 진행하며 느낀 바로는 dynamic으로 명시하는 것이 좋았다 key에 무슨 내용을 담을지 모르는 상태라면🤭
void main() {
Map<String, dynamic> Hyoeun = {
// Map을 작성할 땐 중괄호를 사용한다!
'name': 'Hyoeun Lee',
'nickname': '1hyoeun3',
'age': 24,
'major': 'BA',
};
print(Hyoeun['major']); // Map을 호출할 땐 대괄호를 사용한다!
Hyoeun['school'] = 'Dongduk'; // 새로운 값 할당
Hyoeun.addAll({'city': 'Seoul'}); // 새로운 값 할당
Hyoeun.keys
}
Set
순서 X / 중복값 허용 X
중괄호로 선언
데이터를 모아놓고 사용하는 collection > enum type과 유사
Set<String> members = {'D', 'A', 'C', 'B'};
print(members);
var names = <String>{};
names.addAll(members); // 빈 Set에 members 요소 추가
names.add('E'); // E 값 추가
print(names.elementAt(1)); // A
Collection 추가
- 대괄호 [ ]는 List의 특성을, 중괄호 { }는 Map의 특성을 가졌다고 보면 된다
- iterable = 아이템에 순차적으로 접근 및 반복(loop) 가능한 자료구조
Conditions
condition = 조건문
if-else if-else
int score = 100;
if (score >= 90) {
print('A');
} else if (score >= 80) {
print('B');
} else if (score >= 70) {
print('C');
} else {
print('F');
}
Switch-case
void main() {
var int grade = 90;
switch (grade) {
case 90:
case 80:
case 70: // 동일한 값을 반환할 경우 이런 식으로 작성하면 된다
print('국가장학금 신청을 위한 최소 학점을 취득하였습니다.');
break;
default:
print('국가장학금 신청이 어려운 학점입니다.');
}
}
사실 각기 다른 case인데 동일한 코드를 실행한다면 굳이 Switch문을 사용할 필요가 없는 것 아닐까 싶지만 알아두면 요긴하게 쓸 수도 있으니 적어보았다!
case에는 연산자를 사용할 수 없다! 말 그대로 케이스별로 용이하게 확인할 수 있고자 작성하는 코드이므로 필요하다면 if-else 사용할 것!
Switch expression
void main() {
String engLastName = 'Lee';
String korLastName = switch (engLastName) {
'Kim' => '김',
'Lee' => '이',
'Park' => '박',
_ => '흔하지 않은 성씨입니다.', // default 값은 underscore로 표현
};
print(korLastName);
}
삼항연산자(conditional operator)
(조건식) ? trueValue : falseValue
삼항연산자를 그대로 번역하면 ternary operator인 까닭에 보통 ternary로 부르지만 삼항연산자가 하나 더 있는 Dart에선 conditional operator로 부르는 것이 적절하다
int number = 20;
print( (number == 20) ? '20입니다.' : '20이 아닙니다.');
마치며
- parameter와 argument
def plusFunction(a, b): // a와 b는 parameter
return a + b
plusFunction(10, 20) // 10과 20은 argument
- Map에 nested map 생성 시 대괄호를 사용하여 value 값을 출력할 수 있다
Map<String, dynamic> student = {
'name': 'Hyoeun',
'id': '1hyoeun3',
'grades': {'math': 3.5, 'history': 4.0}
};
print('history 과목 학점: ${student['grades']['history']}'); // 대괄호를 사용해 Key 값을 두 번 입력하면 nested map의 value 값이 출력된다
- Map에서 새로운 key와 value 값을 추가하려면 addAll method를 사용하면 된다
Map<String, dynamic> country = {
'name': 'Indonesia',
'capital': 'Jakarta',
'population': 563254125
};
print('original: $country');
country.addAll({'currency': 'IDR'});
print('add currency: $country');
Share article