다트에 입문하기에 앞서 플러터 개발 환경 구축에 대해 궁금하신 분은 이전 글을 참조하시면 될 것 같습니다.
2023.02.15 - [독서/IT・컴퓨터] - [코드팩토리의 플러터 프로그래밍] 0장. 플러터(flutter) 개발 환경 구축
[코드팩토리의 플러터 프로그래밍] 0장. 플러터(flutter) 개발 환경 구축
모바일 개발을 하고 싶었는데 시작도 안 해보고 있었다가, 최근에 플러터에 관심이 생겨서 플러터를 배워보려고 합니다.🤓 처음엔 공식문서만 보면서 하려고 했는데 빠르게 배우고 싶어서 도
zzingonglog.tistory.com
다트 공식 문서입니다.
Dart documentation
Learn to use the Dart language and libraries.
dart.dev
일단 앱을 만들어서 완성해 보는 것이 목적이기 때문에 책을 통해 핵심적인 부분만 빠르게 배우는 것을 목표로 할게요.
다트 언어에 대해 장점은 아래와 같습니다.
- UI 제작에 최적화
- 완전한 비동기 언어, 아이솔레이트를 이용한 동시성 기능도 제공
- 널 세이프티, 스프레드 기능, 컬렉션 if 등 효율적인 UI 코딩
- 핫 리로딩 기능
- 멀티플랫폼에서 로깅, 디버깅 가능
- AOT 컴파일이 가능하여 어떤 플랫폼에서든 빠른 속도
- 자바스크립트로의 완전한 컴파일 제공
- 백엔드 프로그래밍 지원
지금은 무슨 말인지 잘 모르겠지만, 직접 해봐야 와닿는 부분이겠죠.😄
플러터를 하기 위해서 필수인 Dart 언어 문법을 간단하게 정리하겠습니다.
저는 책에서 추천해 준 사이트 dartpad를 이용하여 문법 테스트를 해보았어요.
브라우저에서 바로바로 테스트하고 실행해 볼 수 있어서 굉장히 편리합니다.
DartPad
dartpad.dev
1. 기초 문법
1) 주석, 문자열 출력, var, dynamic
다른 언어들과 마찬가지로 모든 프로그램의 시작점인 void main() 함수를 사용합니다.
print 함수로 문자열을 출력하며, 문자열을 홑따옴표(' ') 로도 감쌀 수 있는 점을 확인할 수 있습니다. 물론 큰따옴표(" ")도 사용가능합니다.
var와 dynamic 키워드는 변수 선언 시 사용하며 변수에 값이 들어갈 때 값을 자동으로 추론하는 기능을 제공합니다.
단, 차이점은 var는 처음 초기화된 값의 타입과는 다른 타입으로 대입하려고 하면 오류가 나지만, dynamic은 변수의 타입이 고정되지 않고 대입이 가능합니다.
따라서 dynamic 키워드는 문자열을 대입했다가 int 타입의 데이터로 바꿔도 이상이 없이 잘 출력됩니다.
[코드]
void main() {
//한 줄 주석 사용하기
/*
* 여러 줄 주석 사용하기
* 중간 줄은 관행상 *을 사용합니다.
* */
/// 슬래시 세 개를 사용하여 문서 주석 사용하기
/// IDE에서 문서로 인식됩니다.
print('hello world'); //문자열 출력
//var 키워드 사용하기
var name = '찐공 테스트';
print(name);
name = '홍길동';
print(name);
//name = 1; //오류
//print(name); //오류
//dynamic 키워드 사용하기
dynamic name2 = '홍길동';
name2 = 1;
print(name2);
}
[결과]
hello world
찐공 테스트
홍길동
1
2) final, const
final, const는 변수를 상수로 만드는 기능을 제공합니다.
final은 런타임 상수이고 const는 빌드타임 상수입니다.
코드를 실행하지 않은 상태에서 값이 확정되면 const, 코드가 실행되는 순간에 값이 확정되면 final을 사용하면 된다고 합니다.
예를 들면 현재시간을 구하는 함수는 런타임 함수로서 final 키워드를 사용하여 대입해야 합니다.
const를 사용하면 빌드타임에 값을 알아야 해서 현재시간을 구하는 함수와 같이 런타임 이후 확정되는 값은 const로 지정된 변수에 저장할 수 없습니다.
[코드]
void main() {
final String name = '테스트1';
//name = '값수정1'; //오류. 초기화 후 값을 변경할 수 없습니다.
const String name2 = '테스트2';
//name2 = '값수정2'; //오류. 초기화 후 값을 변경할 수 없습니다.
final DateTime now = DateTime.now();
print(now);
//const DateTime now2 = DateTime.now(); //오류. 런타임 시에만 반환 되는 값은 const로 지정 불가합니다.
}
[결과]
2023-02-18 00:32:34.105
3) 변수 타입
c++과 마찬가지로 String, int, double, bool 자료형을 지원합니다.
2. 컬렉션
컬렉션 타입은 서로의 타입으로 자유롭게 형변환이 가능하다는 큰 장점이 있습니다.
List, Map, Set과 같은 것들인데요.
라이브러리들에 대해 더 자세히 알고 싶다면 dart api를 참고하시면 됩니다.
Dart - Dart API docs
Welcome to the Dart API reference documentation, covering the Dart core libraries. These include: dart:core: Core functionality such as strings, numbers, collections, errors, dates, and URIs. dart:html: DOM manipulation for web apps (available only to web
api.dart.dev
1) List
리스트에 값을 대입할 때 대괄호[ ]를 이용한다는 점을 주의하면 될 것 같습니다.
(1) add()
매개변수에 값을 입력하여 리스트의 끝에 데이터를 추가합니다.
[코드]
void main() {
List<String> foodList = ['피자','햄버거','치킨'];
print(foodList);
print(foodList[0]);
print(foodList[2]);
print(foodList.length);
foodList[2] = '짜장면';
print(foodList);
//add(): 리스트의 끝에 값 추가
foodList.add('콜라');
print(foodList);
}
[결과]
[피자, 햄버거, 치킨]
피자
치킨
3
[피자, 햄버거, 짜장면]
[피자, 햄버거, 짜장면, 콜라]
(2) where()
리스트를 순회하면서 특정 조건에 맞는 값만 필터링합니다.
매개변수에 함수를 입력해야 하며 입력된 함수는 기존 값을 하나씩 매개변수로 입력받습니다.
(여기서 함수는 익명함수, 람다함수라는 것인데 이 부분은 5. 함수와 람다에서 설명합니다.)
리스트 순회가 끝나면 필터링된 값들로만 구성된 이터러블(iterable)이 반환됩니다. 이터러블은 출력 시 ( )를 사용하는 부분을 확인할 수 있습니다.
반환된 이터러블은 toList()를 사용하면 다시 리스트로 변환할 수 있습니다.
[코드]
void main() {
List<String> foodList = ["피자",'햄버거','치킨','짜장면','콜라'];
final newList1 = foodList.where((name) => name == '피자' || name == '콜라',);
//iterable로 반환
print(newList1);
//toList(): iterable을 List로 변환
print(newList1.toList());
}
[결과]
(피자, 콜라)
[피자, 콜라]
(3) map()
리스트를 순회하면서 요소 값의 변경이 가능합니다.
매개변수에 함수를 입력해야 하며 입력된 함수는 리스트 값을 하나씩 매개변수로 입력받습니다.
반환하는 값은 변경된 값으로 구성된 iterable이 반환됩니다.
아래 코드는 각 요소들을 순회하면서 앞에 새로운 문자열을 추가하고 있습니다.
여기서 $name는 $변수명 형태로 사용하는데 문자열 내부에서 사용하면서 해당 위치에 값이 대체됩니다.
[코드]
void main() {
List<String> foodList = ["피자",'햄버거','치킨','짜장면','콜라'];
final newList2 = foodList.map((name) => '맛있는 $name');
print(newList2);
}
[결과]
(맛있는 피자, 맛있는 햄버거, 맛있는 치킨, 맛있는 짜장면, 맛있는 콜라)
(4) reduce()
역시 매개변수로 함수를 입력받습니다.
단, 리스트를 순회하면서 값을 누적하여 누적한 값을 List멤버의 타입과 동일한 타입으로 반환합니다.
리스트를 구성하는 값들의 타입과 반환되는 리스트를 구성할 값들의 타입이 완전히 같아야 합니다.
첫 번째 매개변수인 value에는 첫 번째 요소 값이 들어가고 두 번째 매개변수인 element에는 두 번째 요소 값이 들어갑니다.
이후부터는 value에는 앞서 만들어진 값이 들어가게 되고 element에는 세 번째 요소값이 들어가는 식으로 동작합니다.
만들어진 리스트를 출력해 보면 구성하는 값과 타입이 동일한 문자열인 것을 확인할 수 있습니다.
[코드]
void main() {
List<String> foodList = ["피자",'햄버거','치킨','짜장면','콜라'];
final allList1 = foodList.reduce((value, element) => value + ', ' + element);
print(allList1);
}
[결과]
피자, 햄버거, 치킨, 짜장면, 콜라
(5) fold()
reduce()와 기본적으로 실행되는 방법은 동일합니다.
첫 번째 매개변수에 시작할 값을 지정하고, 두번째 매개변수에 함수를 입력합니다.
단 시작값은 value에 첫 번째 인자로 들어가게 됩니다. 그리고 element은 첫번째 요소부터 들어가게 되는데 element.length이므로 '피자'의 문자열 길이는 2입니다. 모든 요소들을 순회하며 문자열 길이 합을 구하는 코드입니다.
fold는 어떠한 타입이든 반환할 수 있습니다.
예시코드에서도 정수형을 출력하는 것을 확인할 수 있습니다.
[코드]
void main() {
List<String> foodList = ["피자",'햄버거','치킨','짜장면','콜라'];
final allList2 = foodList.fold(0, (value, element) => value + element.length);
print(allList2);
}
[결과]
12
2) Map
Map 역시 다른 언어에서 사용되는 Map 개념과 동일합니다. 키(key), 값(value)으로 자료를 저장하는 자료구조입니다.
[코드]
void main() {
Map<String, String> firstName = {
'Kim' : '김씨',
'Park' : '박씨',
'Kwon' : '권씨',
};
print(firstName['Kim']);
print(firstName['Park']);
//전체 키를 반환
print(firstName.keys);
//전체 값을 반환
print(firstName.values);
}
[결과]
김씨
박씨
(Kim, Park, Kwon)
(김씨, 박씨, 권씨)
3) Set
Set은 집합으로 생각하면 되고, 데이터의 중복이 불가하기 때문에 유일한 값들만 저장합니다.
Set을 출력해 보면 { }로 감싸 출력되는 것을 확인할 수 있습니다.
어떤 원소가 Set안에 들어있는지 확인하려면 contain()을 이용하면 됩니다.
또한 Set을 List로 변경하고 싶다면 toList(), 반대로 List -> Set으로 변경하고 싶다면 from()을 사용합니다.
[코드]
void main() {
Set<String> colors = {'red', 'blue', 'orange','black','yellow','yellow'};
print(colors);
print(colors.contains('red'));
print(colors.toList());
List<String> months = ['Jan','Apr','Jul','Sep','Dec'];
//List -> Set으로 변환
print(Set.from(months));
}
[결과]
{red, blue, orange, black, yellow}
true
[red, blue, orange, black, yellow]
{Jan, Apr, Jul, Sep, Dec}
4) enum
열거형(enum)은 한 변수가 가질 수 있는 값을 미리 설정해 두고 그 값만 가질 수 있도록 합니다.
변수가 가져야 하는 값이 제한적일 때 자주 사용하지요.
열거형 이름.values는 열거형에 정의된 모든 값들을 리스트로 변환해줍니다.
[코드]
enum Answers {
yes,
no,
none,
}
void main() {
Answers answer = Answers.yes;
print(answer);
print(Answers.values);
}
[결과]
Answers.yes
[Answers.yes, Answers.no, Answers.none]
3. 연산자
기본 연산자, 논리연산자, 비교연산자들은 다른 언어와 완전히 동일하기 때문에 생략하고, 다트언어에서 볼 수 있는 독특한 부분인 null 관련 연산자와 타입 비교연산자에 대해서 정리해 볼게요.
1) null 관련 연산자
null은 아무것도 없음을 뜻하는 것으로, 0과는 다른 의미입니다. 다트 언어에서는 변수 타입이 null 값을 가지는지 여부를 직접 지정해주어야 합니다. 기본적으로는 null값이 지정될 수 없습니다. 타입 뒤에 ?를 추가해 주어야 null값이 저장될 수 있습니다.
[코드]
void main () {
double? number1 = null;
double number2 = null; //오류
}
또한 현재 변수의 값이 null일 때에만 값을 대입하는 ??= 연산자가 있습니다.
아래 코드에서 number의 값이 null일 때에만 변수에 값이 대입되고 그 후 ??= 연산자로 4를 대입하려고 하면 값이 변경되지 않습니다.
[코드]
void main () {
double? number; //자동으로 초기값은 null
print(number);
number ??= 3;
print(number);
number ??= 4;
print(number);
}
[결과]
null
3
3
2) 타입 비교 연산자
is 키워드를 사용하여 변수의 타입을 비교할 수 있습니다. 비교 후 리턴되는 값은 bool 타입입니다.
is! 를 사용하면 반대를 의미하여 같지 않은지에 대한 결과를 리턴합니다.
[코드]
void main () {
int number = 1;
print(number is int);
print(number is String);
print(number is! int);
print(number is! String);
}
[결과]
true
false
false
true
4. 제어문
if, switch, while 문은 역시 다른 언어와 동일하기 때문에 기본 설명은 생략합니다.😁
for문은 아래 코드와 같이 2가지 방식을 지원합니다.
[코드]
void main () {
List<int> list = [1,2,3];
for (int i = 0; i < list.length; i++) {
print(list[i]);
}
for (int i in list) {
print(i);
}
}
[결과]
1
2
3
1
2
3
5. 함수와 람다
1) 함수의 일반적인 특징
다트에서 함수를 정의할 때는 2가지 방법으로 정의를 내릴 수 있습니다.
(1) 고정된 매개변수 (=포지셔널 파라미터)
일반적인 방법으로 파라미터가 나열된 순서대로 인자에 값이 들어가는 방식입니다.
[코드]
int addTwoNumbers(int a, int b) {
return a + b;
}
void main() {
print(addTwoNumbers(1, 2));
}
(2) 이름이 있는 매개변수 (=네임드 파라미터)
순서와 관계없이 지정하고 싶은 매개변수의 이름을 이용해 값을 입력할 수 있습니다.
중괄호 { } 와 required 키워드를 사용하여 네임드 파라미터를 지정할 수 있어요.
함수를 사용할 때 인자로 매개변수의 이름을 이용하여 값을 전달하므로 매개변수의 순서는 상관없습니다.
required 키워드는 매개변수가 null값이 불가능한 타입이면 기본값을 지정해 주거나 필수로 입력해야 한다는 의미입니다.
[코드]
int addTwoNumbers({
required int a,
required int b,
}) {
return a + b;
}
void main() {
print(addTwoNumbers(a: 1, b: 2));
}
(3) 함수의 매개변수에 디폴트값 지정하기
- 고정된 매개변수 (=포지셔널 파라미터)
포지셔널 파라미터방식에서 기본값(디폴트 값)을 지정하는 방법은 [ ]를 사용합니다.
[코드]
int addTwoNumbers(int a, [int b = 2]){
return a + b;
}
void main() {
print(addTwoNumbers(1));
}
[결과]
3
- 이름이 있는 매개변수 (=네임드 파라미터)
네임드 파라미터에서 디폴트 값을 지정하려면 required 키워드를 생략하고 등호에 디폴트 값을 입력하면 됩니다.
[코드]
int addTwoNumbers({
required int a,
int b = 2,
}) {
return a + b;
}
void main() {
print(addTwoNumbers(a: 1));
}
[결과]
3
- 섞어서 사용하기
포지셔널 파라미터와 네임드 파라미터를 섞어서 사용할 수 있습니다.
단 포지셔널 파라미터가 네임드 파라미터보다 반드시 먼저 위치해야 합니다.
[코드]
int addThreeNumbers(int a, {
required int b,
int c = 4,
}) {
return a + b + c;
}
void main () {
print(addThreeNumbers(1, b: 3));
}
[결과]
8
2) 익명 함수와 람다 함수
익명 함수와 람다함수는 둘 다 함수 이름이 없으며 일회성으로 사용됩니다. 통상 많은 언어에서 익명함수와 람다함수를 구분하지만 다트에서는 구분하지 않습니다.
함수의 형태는 다음과 같습니다. 표현 방식만 다를 뿐 기능은 동일하다고 생각하시면 됩니다.
익명 함수 | 람다 함수 |
(매개변수) { 함수 바디 } |
(매개변수) => 단 하나의 스테이트먼트 |
익명 함수에서 중괄호 { } 를 빼고 => 기호를 추가한 것이 람다 함수입니다.
매개 변수는 없거나 하나 이상이어도 됩니다. 단 람다 함수는 스테이트먼트가 단 한 개(=명령 단위가 하나)여야 합니다.
콜백 함수나 리스트의 map(), reduce(), fold() 함수에서 일회성 로직을 작성해야 할 때 주로 사용합니다.
코드 1과 코드 2는 동일한 기능의 코드입니다.
[코드 1]
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
final allMembers = numbers.reduce((value, element) {
return value + element;
});
print(allMembers);
}
[결과]
15
[코드 2]
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
final allMembers = numbers.reduce((value, element) =>
value + element);
print(allMembers);
}
[결과]
15
3) typedef와 함수
typedef 키워드는 함수 선언부를 정의하는 키워드이며, 선언부만 정의하고 바디는 정의하지 않습니다.
다트에서는 함수를 값처럼 사용할 수 있습니다.
[코드]
typedef Operation = void Function(int x, int y);
void add(int x, int y) {
print('결괏값 : ${x + y}');
}
void subtract(int x, int y) {
print('결괏값 : ${x - y}');
}
void calculate(int x, int y, Operation oper) { //함수를 매개변수로 사용 가능
oper(x, y);
}
void main() {
Operation op = add;
op(1, 2);
op = subtract;
op(1, 2);
calculate(1, 2, add);
}
[결과]
결괏값 : 3
결괏값 : -1
결괏값 : 3
여기까지 기초 문법에 대해 정리해 보았습니다.
다음 장은 객체지향 프로그래밍에 대해 배워보겠습니다.😉
'Programming > Dart & Flutter' 카테고리의 다른 글
플러터 앱에 Firebase 연동하기 (0) | 2024.02.22 |
---|---|
[코드팩토리의 플러터 프로그래밍] 3장. 다트 비동기 프로그래밍 (0) | 2023.02.23 |
[코드팩토리의 플러터 프로그래밍] 2장. 다트 객체지향 프로그래밍 (0) | 2023.02.22 |
[코드팩토리의 플러터 프로그래밍] 0장. 플러터(flutter) 개발 환경 구축 (0) | 2023.02.15 |