1단계 다트 언어 마스터하기

송기영·2023년 11월 21일
0

플러터

목록 보기
3/25

본글은 코드팩토리의 플러터 프로그래밍 도서를 보고 공부한 내용을 정리한 내용입니다.

1. 다트 소개

구글이 개발한 다트 프로그래밍 언어로, 크롬에 Dart 가상 머신을 심어 자바스크립트를 대체하려고 시도했으나, 웹 개발에 혼란을 가져온다는 여론을 극복하지 못하고 결국 자바스크립트로 완전 컴파일 가능하게 만드는데 그쳤다.

1.1. 장점

  • UI를 제작하는데 최적화되어 있다. 완전한 비동기 언어이며 이벤트 기반이고, 아이솔레이트를 이용한 동시성 기능도 제공
  • 널 세이프티, 스프레드 기능, 콜렉션, if문 등 효율적으로 UI를 코딩할 수 있는 기능을 제공한다.
  • 핫 리로딩을 통해 코드의 변경 사항을 즉시 화면에 반영해 볼 수 있다.
  • 멀티 플랫폼에서 로깅, 디버깅, 실행이 가능하다.
  • AIT 컴파일이 가능하기 때문에 어떤 플랫폼에서든 빠른 속도를 자랑한다.
  • 자바스크립트로의 완전한 컴파일을 지원한다.
  • 백엔드 프로그래밍을 지원한다.

1.2. 기초 문법

주석 작성, 콜솔출력, 변수를 선언하는 방법, 변수의 타입을 알아보자.

1.2.1. 메인 함수

다트는 프로그램 시작점인 엔트리 함수 기호로 main()을 사용한다.

void main() {

}

1.2.2. 주석

프로그램을 실행했을때 프로그램에서 코드로 인식하지 못하는 부분, 일반적으로 개발자끼리 소통 및 코드에 대한 정보를 남기는데 사용, 주석 기호로 //, /**/, ///를 사용한다.

void main() {
	// 한줄 주석

	/*
	 * 여러줄 주석
   */

	/// 문서 주석을 작성할 수 있따.
}

1.2.3. print() 함수

문자열을 콘솔에 출혁하는 함수

void main() {
	print("Hello world");
}

1.2.4. var를 사용한 변수 선언

var 변수명 = 값; 형식으로 선언한다. 변수의 값이 들어가면 자동으로 타입을 추론한다.

실제 코드가 컴파일 될때는 추론된 타입으로 var이 치환된다.

var name = "송기영";
print(name);

name = "카이";
print(name);

// 다음과 같이 중복되는 변수명은 재선언 불가능
var name = "재선언";

1.2.5. dynamic를 사용한 변수 선언

var은 한번 타입을 유추하면 추론된 타입이 고정된다. 따라서 다른 변수 타입 값을 변수에 다시 저장하려고 하면 에러가 난다. dynamic은 이 부분을 해결해준다.

dynamic name = "송기영";
name = 1;

1.2.6. final/const를 사용한 변수 선언

변수의 값을 처음 선언 후 변경할 수 없다.

const String name = "송기영";
final String name2 = "송기영2";

// 아래 모두 값 변경 불가능
name = "카이";
name2 = "카이2";

final은 런타임, const는 빌드 타임 상수로 코드를 실행하지 않은 상태에서 값이 확정되면 const를, 실행될 때 확정되면 final을 사용한다. 즉 const는 값이 정해져있는 변수

final check = test();

// 에러
const check = test();

int test() {
	return 42;
}

1.2.7. 변수 타입

var을 사용해도 되지만 변수 타입을 명시해주면 코드가 직관적이여서 유지보수에 용이하다.

String name = "송기영";
int isInt = 10;
double isDouble = 2.5;
bool isTrue = true;

1.3. 컬렉션

하나의 변수에 여러 값을 저장할 수 있는 타입으로 아래와 같은 타입이 존재한다.

List - 여러 값을 순서대로 저장

Map - 특정 키값을 기반으로 빠르게 값을 검색

Set - 중복된 데이터를 제거

1.3.1. List 타입

여러 값을 순서대로 한 변수에 저장할 때 사용한다. 구성 단위를 원소라고하며, 리스트명[인덱스] 형식으로 특정 원소에 접근 가능하다.

List<String> blackPinkList = ["리사", "지수", "제니", "로제"];
print(blackPinkList);
print(blackPinkList[0]); // 리사
print(blackPinkList[blackPinkList.length - 1]); // 로제

add() 함수

List에 값을 추가할 때 사용하며 추가 하고 싶은 값을 매개변수에 입력한다.

List<String> blackPinkList = ["리사", "지수", "제니", "로제"];
blackPinkList.add("기영");

where() 함수

List에 있는 값들을 순서대로 순회하면서 특정 조건에 맞는 값만 필터링 하는데 사용한다. 조건에 맞으면 true를 반환하고 값을 유지하고, false를 반환하면 값을 버린다.

List<String> blackPinkList = ["리사", "지수", "제니", "로제"];
final newList = blackPinkList.where(
	(name) => name == "리사" || name == "지수", // 리사 또는 지수만 유지
);
print(newList); // (리사, 지수)
print(newList.toList()); // [리사, 지수]

map() 함수

List에 있는 값들을 순서대로 순회하면서 값을 변경할 수 있다.

List<String> blackPinkList = ["리사", "지수", "제니", "로제"];
final newList = blackPinkList.map(
	(name) => "블랙핑크 $name", // 리사 또는 지수만 유지
);
print(newList); // (블랙핑크 리사, 블랙핑크 지수, 블랙핑크 제니, 블랙핑크 로제)
print(newList.toList()); // [블랙핑크 리사, 블랙핑크 지수, 블랙핑크 제니, 블랙핑크 로제]

reduce() 함수

List에 있는 값들을 순서대로 순회하면서 매개변수에 입력된 함수를 실행한다. 다만 값을 쌓아가는 특징이 있다.

List<String> blackPinkList = ["리사", "지수", "제니", "로제"];
final allMembers = blackPinkList.reduce((value, element) => value +', ' + element);
print(allMemebers); // 리사, 지수, 제니, 로제

fold() 함수

reduce() 함수와 실행되는 논리는 똑같다. 하지만 reduce() 함수는 리스트 요소들의 타입이 같아야 하지만 fold() 함수는 어떤 타입이든 반환할 수 있다.

List<String> blackPinkList = ["리사", "지수", "제니", "로제"];
final allMemebers = blackPinkList.fold<int>(0, (value, element) => value + element.length);
print(allMemebers); // 8

reduce() 함수와 달리 fold() 함수는 첫번째 매개변수에 입력된 값이 초기값으로 사용된다.

1.3.2. Map 타입

키와 값의 짝을 저장한다. 자바스크립트의 object와 같은 형태로 Map<키의 타입, 값의 타입> 맵이름 형식으로 생성한다.

Map<String, String> dictionary = {
	"Harry Potter": "해리 포터",
	"Ron Weasley" : "론 위즐리",
	"Hermione Ganger": "헤르미온느 그레인저",
};

print(dictionary); // {Harry Potter: 해리 포터, Ron Weasley: 론 위즐리, Hermione Ganger: 헤르미온느 그레인저}
print(dictionary["Harry Potter"]);
print(dictionary.keys); // (Harry Potter, Ron Weasley, Hermione Ganger)
print(dictionary.values); // (해리 포터, 론 위즐리, 헤르미온느 그레인저)

1.3.3. Set 타입

키와 값의 조합이며 중복 없는 값들의 집합으로, Set<타입> 세트이름 형식으로 생성한다. 중복을 방지하므로 유일한 값들만 존재하는걸 보장한다.

Set<String> blankPink = {"로제", "지수", "리사", "제니"}; //

print(blankPink);
print(blankPink.contains("로제"));
print(blankPink.toList());  // 리스트로 변환
  
List<String> blankPink2 = ["로제", "지수", "지수"];
var check = Set.from(blankPink2); // 이렇게 적용하면 기존 blankPink2 값도 변경이 될지 궁금했다.
print(blankPink2); // [로제, 지수, 지수]
print(check); // {로제, 지수}

1.3.4. enum 타입

한 변수의 값을 몇가지 옵션으로 제한하는 기능으로, 선택지가 한정적일 때 사용한다.

String으로 완전 대체가 가능하지만 기본적으로 자동완성을 지원하고 정확히 어떤 선택지가 존재하는지 정의해둘 수 있기 때문에 유용하다.

enum Status {
	approved,
	pending,
	rejected
}

1.4. 연산자

수치 연산자, null값 입력 관련 연산자, 값 비교 연산자, 타입 비교 연산자, 논리 연산자

1.4.1. 기본 수치 연산자

double number = 2;
print(number + 2);
print(number - 2);
print(number * 2);
print(number / 2);
print(number % 2);

number++;
number--;
number += 2;
number -= 2;
number *= 4;
number /= 2;

1.4.2. null 관련 연산자

null은 아무 값도 없음을 뜻한다. 타입 뒤에 ‘?’를 추가해줘야 null값이 저장될 수 있다.

double? number1 = 1; // null 허용
double? number1; // 자동으로 null값 지정
number1 ??= 3;   // 기존 값이 null일 때만 저장
number1 ??= 4;   // 기존 값이 null이 아니기 때문에 3이 유지된다.
double number2 = null; // 에러

1.4.3. 값 비교 연산자

int number1 = 1;
int number2 = 2;

print(number1 > number2);  // false
print(number1 < number2);  // true
print(number1 >= number2); // false
print(number1 <= number2); // true
print(number1 == number2); // false
print(number1 != number2); // true

1.4.4. 타입 비교 연산자

is 키워드를 사용하면 변수의 타입을 비교할 수 있다.

int number = 1;
print(number is int);     // true
print(number is String);  // false
print(number is! int);    // false
print(number is! String); // true

1.4.5. 논리 연산자

and와 or을 의미한다.

bool result1 = 12 > 10 && 1 > 10; // true
bool result2 = 12 > 10 && 0 > 1;  // false
bool result3 = 12 > 10 || 1 > 0;  // true
bool result4 = 12 > 10 || 0 > 1;  // true
bool result5 = 12 < 10 || 0 > 1;  // false

1.5. 제어문

1.5.1. if문

원하는 조건 기준으로 다른 코드를 실행하고 싶을때 사용한다.

int number = 2;
if (number % 3 == 0) {
	print('3의 배수');
} else if (number % 3 == 1) {
	print('나머지 1');
} else {
	print('맞는 조건 없음');
}

1.5.2. switch문

입력된 상수 값에 따라 case 블록을 수행, break 키워드를 사용하면 switch문 밖으로 나갈 수 있다.

enum과 함께 사용하면 유용하다.

enum Status {
	approved,
	pending,
	rejected
}

void main() {
	Status status = Status.approved;

	switch (status) {
		case Status.approved:
			print('승인');
			break;
		case Status.pending:
			print('대기');
			break;
		case Status.rejected:
			print('거절');
			break;
		default:
			print('알 수 없음');
	}
}

1.5.3. for문

for (int i = 0; i < 3; i++) {
	print(i);
}

List<int> numberList = [1,2,3];

for (int number in numberList) {
	print(number);
}

1.5.4. while, do…while문

조건을 기반으로 반복문을 행한다. 조건이 true면 실행, false면 멈춘다.

do…while은 실행한 후 조건을 확인한다.

int number = 0;

while (number < 10) {
	print(number);
	number += 1;
}

do {
  number += 1;
} while(number <10);

1.6. 함수와 람다

1.6.1. 함수의 일반적인 특징

함수는 여러 곳에서 재활용이 가능하며, 반환값이 없을 때에는 void 키워드를 사용한다.

int addTwoNumber(int a, int b) {
	return a + b;
}

네임드 파라미터(자바스크립트의 object 같은것을 의미)를 지정하려면 중괄호 {}와 required 키워드를 사용해야 한다.

int addTwoNumber({
	required int a,
	required int b,
}) {
	return a + b;
}

print(addTwoNumber(a:1, b:2));

required 키워드는 매개변수가 null값이 불가능한 타입이면 기본값을 지정해주거나 필수로 입력해야 한다는 의미이다.

포지셔널 파라미터는 일반적인 순서대로 매개변수를 가지는 것을 의미하며 기본값을 주기 위해서는 []기호를 사용한다.

int addTwoNumber(int a,	[int b = 2]) {
	return a + b;
}

print(addTwoNumber(a:1));

포지셔널 파라미터와 네임드 파라미터를 같이 사용할 때는 포지셔널 파라미터가 먼저 위치해야한다.

int addTwoNumber(int a, {
	required int b,
	int c = 3,
}) {
	return a + b + c;
}

print(addTwoNumber(1, b:3, c:4));

1.6.3. 익명 함수와 람다 함수

List<int> numbers = [1,2,3,4,5];

// 익명함수
final allMembers = numbers.reduce((value, element) {
	return value + element;
})

// 람다함수
final allMembers2 = numbers.reduce((value, element) => value + element);

1.6.4. 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 main() {
	Operation oper = add;
	oper(1,2);
	oper = subtract;
	oper(2,1);
}

다트에서 함수는 일급 객체로 함수를 값처럼 사용할 수 있다.

typedef Operation = void Function(int x, int y);

void add(int x, int y) {
	print(x + y);
}

void calculate(int x, int y, Operation oper) {
	oper(x, y)
}

void main() {
	calculate(1,2, add);
}

1.7. try…catch

try{
	// 에러가 없을때
	final String name = "기영";

	// 고의적인 에러 발생시 catch에 잡힘.
	throw Exception('Error);
}catch(e){
	print(e);
}

다른 객체지향 언어와 비슷하면서도 자바스크립트의 기능을 포함한것을 볼 수 있었음. 특히 일급 객체 부분에서 자바스크립트를 대체하려고 했음이 보였다.

추가특징

2023.11.27. 추가
다트의 내용을 공부하다보니 다트는 자바스크립트와 같이 싱글 스레드 기반 언어로 이벤트 루프(Event Loop) 및 FutureStream과 같은 비동기적인 패턴을 활용하여 처리된다고 한다.

profile
업무하면서 쌓인 노하우를 정리하는 블로그🚀 풀스택 개발자를 지향하고 있습니다👻

0개의 댓글