Post

Flutter를 위한 Dart 공부

1. Variables

dart와 flutter는 구글이 개발했기때문에 flutter를 최적화하여 dart를 빠르게 할 수 있다. ⇒ 프레임워크가 필요하면 바로 언어에서 개발

JIT(Just In TIme) 바로 실행결과로 보여줌

AOT(Ahead Of TIme) 바로 빠른 기계어로 컴파일해줌.

모든 코드는 main 함수 안에 들어가야한다.

1.1 The Var Keyword

var 지역함수 쓸때 사용

class에서 선언할때 String등 사용

1
2
3
var name = “씅찬”; //을 해도 dart는 String타입으로 인지한다.

name = sseung; //같은 타입으로 update만 한다면 가능

1.2 Dynamic Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dynamic(var) name; //으로 선언하면

name = ‘승찬’;
name = 12;
name = true;
//다 사용 가능
String? sseung = 'sseung';
sseung = null;

//sseung도되고 null도 될 수 있다 (사용법 ⇒ 변수?)

//기본적으로 모든 변수는 non-nullable null이 될 수 없다.

if(sseung != null) {
	sseung.isNotEmpty;
}

//위 아래 같은 뜻
sseung?.isNotEmpty;

여러가지 타입을 가질 수 있는 변수에 쓰는 키워드이다. (해당 변수의 타입을 알 수 없을 때 주로 사용)

변수를 선언할 때 dynamic을 쓰거나 값을 지정하지 않으면 dynamic 타입을 가진다.

1.3 Nullable Variables

개발자가 null 값을 참조할 수 없도록 하는 것

String뒤에 ?를 붙여줌으로서 name이 String 또는 null이 될 수 있다고 명시해준 것

기본적으로 모든 변수는 non-nullable(null이 될 수 없음)이다.

1
2
3
4
5
6
7
void main() {

String? name = "hello";

name = null;

}

1.4 Final Variables

var대신 final로 변수를 만들게 되면 이 변수는 수정할 수 없게 된다. (딱 한 번만 설절될 수 있음)

자바스크립트의 const랑 비슷하다.

1
2
3
4
5
6
7
8
9
10
11
void main() {

final name = "씅찬";

name = "씅"; // 수정 불가

final String username = "씅찬";

name = "씅찬2"; // 수정 불가

}

1.5 Late Variables (선언 한 뒤, 변수가 나중에 초기화 됨)

초기 데이터 없이 먼저 변수를 생성하고 추후에 데이터를 넣을 때 주로 사용한다.

flutter로 data fecthing을 할 때 유용하다.

late 변수를 만들고, API에 요청을 보낸 뒤에 API에서 값을 보내주면 그 응답값을 late변수에 넣어 사용할 수 있다.

1
2
3
4
5
6
7
void main() {

late final String name;

print(name); // name 변수에 접근 불가

}

1.6 Const Variables (상수)

(const키워드는 컴파일 타임에 평가되므로, 변수는 반드시 선언 시 초기화 되어야 함.) ⇒ 따라서 late const를 같이 쓸 수 없음

dart에서 const는 compile-time constant를 만들어준다.

const는 컴파일할 때 알고 있는 값을 사용해야 한다.

만약 어떤 값인지 모르고, 그 값이 API로부터 오거나 사용자가 화면에서 입력해야 하는 값이라면 그건 const가 아닌 final이나 var가 되어야 한다.

1
2
3
4
5
6
7
void main() {

const name = "씅찬"; // 컴파일 시점에 바뀌지 않는 값

final username=fetchAPI(); // 컴파일 시점에 바뀌는 값

}

const: 컴파일 시점에 바뀌지 않는 값 *(상수)

final: 컴파일 시점에 바뀌는 값 (API에서 받아온 값, 사용자 입력값)

1.7 Recap

변수를 만드는 2가지 방법

1
2
3
4
5
void main() {
var name = "sseung"; // 방법 1
name = "sseung1";
String name2 = "sseung"; // 방법 2
}

final: 값을 재할당하지 못하는 변수를 만듦

dynamic type: 어떤 타입의 데이터가 들어올 지 모를 때 사용함

const: 컴파일 할 때 값을 알고 있는 변수

final: 런타임 중에 만들어질 수 있는 변수

late: final, var, String같은 것들 앞에 써줄 수 있는 수식어로서 어떤 데이터가 올 지 모를 때 사용한다.

2. Data Types

2.0 Basic Data Types(기본 데이터 타입)

아래 타입을 포함한 거의 대부분의 타입들이 객체로 이루어져 있다. (함수도 객체)

이것이 Dart가 진정한 객체 지향 언어로 불리는 이유이다.

1
2
3
4
5
6
7
8
void main() {
String name = "tom";
bool isPlay = true;
int age = 10;
double money = 52.55;
num x = 12;
num y = 1.2;
}

2.1 Lists

List를 사용하는 2가지 방법

1
2
3
4
5
6
7
void main() {

List numbers = [1, 2, 3];

var number2 = [4, 5, 6];

}

List는 collection if와 collection for를 지원한다.

collection if는 List를 만들 때, if를 통해 존재할 수도 안 할 수도 있는 요소를 가지고 만들 수 있다.

마지막에 ‘ , ‘를 쓰면 자동 포맷팅으로 아래와 같이 줄바꿈됨

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void main() {

var giveMeFive = true;

var numbers = [
1,
2,
3,
4,
if (giveMeFive) 5, // giveMeFive가 true이면 5을 넣음
];

// 아래와 같은 기능이다.
if(giveMeFive){
	case1.add(5);
}

print(item);

}

2.2 String Interpolation

변수 사용하는 방법

$달러 기호를 붙이고 사용할 변수를 적어주면 된다.

만약 무언가를 계산하고 싶다면 ${ } 형태로 적어주면 된다.

1
2
3
4
5
6
void main(){
	var name = "씅찬";
	var age = 20;
	var greeting = "hello my name is $name, I'm ${age + 10}";
	print(greeting);
}

2.3 Collection For

Dart는 조건문(if) 및 반복(for)을 사용하여 컬렉션을 구축하는 데 사용할 수 있는 컬렉션 if 및 컬렉션 for도 제공한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void main() {

var oldFriends = ["포엘", "씅찬"];

var newFriends = [

"경환",

"종호",

"소민",

for (var friend in oldFriends) "❤️ $friend"

];

print(newFriends); // [경환, 종호, 소민, ❤️ 포엘, ❤️ 승찬]

}

2.4 Maps

일반적으로 맵은 key와 value를 연결하는 객체다. 키와 값 모두 모든 유형의 객체가 될 수 있다. 각 키는 한 번만 발생하지만 동일한 값을 여러 번 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var player = {

// Key: Value

'name': '씅찬',

'xp': 99.99,

'superpower': false,

};

// Map 생성자를 사용하여 동일한 객체를 만들 수 있다.

Map<int, bool> player = {
	1: true,
	2: false,
	3: true
};

//List안에 Map도 가능
List<Map<String, Object>> players = [
	{'name': '씅찬', 'xp': 13.5},
	{'name': '포엘', 'xp': 53.5},
];

var player2 = Map();

player2['name'] = '씅찬';

player2['xp'] = 99.99;

player2['superpower'] = false;

2.5 Sets

Set에 속한 모든 아이템들이 유니크해야될 때 사용한다.

유니크할 필요가 없다면 List를 사용하면 된다.

set도 두 가지 방법으로 정의할 수 있다.

1
2
3
4
5
6
7
8
9
10
//1. var을 사용

var numbers = {1, 2, 3};

//2. 자료형 명시

Set numbers = {1, 2, 3};

var friends = {'승찬', '은화', '경환', '종호', '소민'};

3. Functions

3.0 Defining a Function

Dart는 진정한 객체 지향 언어이므로 함수도 객체이며 타입이 Function이다 이는 함수를 변수에 할당하거나 다른 함수에 인수로 전달할 수 있음을 의미한다.

1
2
3
4
5
6
7
8
9
10
11
12
// 하나의 표현식만 포함하는 함수의 경우 아래와 같이 단축 구문(화살표)을 사용할 수 있다.

String sayHello(String name) => "Hello ${name} nice to meet you.";

num plus(num a, num b) => a + b;
num minus(num a, num b) => a - b;

void main() { //void: return을 안해도 됨

print(sayHello("씅찬"));

}

3.1 Named Parameters

Named parameters는 명시적으로 required로 표시되지 않는 한 선택 사항이다. 기본값을 제공하지 않거나 required ⇒ Named parameters를 필수로 표시하지 않으면 해당 유형은 기본값이 null이 되므로 null을 허용해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String sayHello(
{
	required String name, //required는 매개변수를 필수로 지정해줘야 한다.
	required int age,
	required String country
}) 
{
	return "${name} / ${age} / ${country}";
}

void main() {

	print(sayHello(name: "씅찬", age: 30, country: "Korea"));

}

3.3 Optional Positional Parameters

Dart에서 [] 은 optional, positional parameter를 명시할 때 사용된다.

name, age는 필수값이고 []를 통해 country를 optional값으로 지정해줄 수 있다.

1
2
3
4
5
6
7
8
9
10
String sayHello(String name,
 int age,
 [String? country = 'Korea'], //String? 으로 not required로 바꿔준다.
 ) => 'Hello $name, you are
$age years old from $country';

void main() {
	var results = sayHello('sseung', 30);
	print(results);
}

3.4 QQ Operator

?? 연산자를 이용하면 왼쪽 값이 null인지 체크해서 null이 아니면 왼쪽 값을 리턴하고

null이면 오른쪽 값을 리턴한다.

1
2
3
4
5
6
7
8
9
10
11
12
//String capitalizeName(String name) => name.toUpperCase();

String capitalizeName(String? name) => 
		name.toUpperCase() ?? '승찬';

void main() {
	String? name;
	name ??= '승찬';
	name = null;
	name ??= 'another';
	print(name); //
}

3.5 Typedef

자료형에 사용자가 원하는 alias를 붙일 수 있게 해준다. (자료형 이름의 별명을 만들 때 사용)

1
2
3
4
5
6
7
8
9
10
11
typedef ListOfInts = List<int>;

//List<int> reverseListOfNumbers(List<int> list) { 
ListofInts reverseListOfNumbers(ListofInts list) { //typedef로 별명을 만들어주고 사용
	var reversed = list.reversed;
	return reversed.toList();
}

void main() {
	print(reverseListOfNumbers([1, 2, 3])); //출력 결과: [3, 2, 1]
}

4 Classes

4.1 Your First Data Class

dart에서 property를 선언할 때는 타입을 사용해서 정의한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Player {
	final String name = 'sseung';
	final int age = 30;
	
	void sayName(){
	// class method안에서는 this를 쓰지 않는 것을 권장한다.
	print("Hi my name is $name");
	}
}
void main(){
	// new를 꼭 붙이지 않아도 된다.
	var player =Player();
	print(player.name); //sseung
	print(sayHello); //Hi my name is sseung
	
	player.name = 'hello';
	print(player.name); //hello

}

4.1 Constructors

Dart에서 생성자는 클래스명과 같아야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 class Player {
	final String name;
	int age;;
	
	/*
	아래와 같은 생성자일 때는 late를 사용한다.
	class Player {
		late final String name;
		late int age; 
	
	Player{String name, int age){
		this.name = name;
		this.age = age;
	} 아래와 같이 한줄로 줄일 수 있다.
	*/
	Player(this.name, this.age);
	
	void sayName(){
	print("Hi my name is $name");
	}
}
void main(){
	var player = Player("승찬", 30);
	var player2 = Player("씅찬", 30);
}

4.2 Named Constructor Parameters

클래스가 너무 거대해질 경우 [3.1 Named Paramters](https://www.notion.so/Dart-b138a403d60345079a098eba0bafe1d0?pvs=21) 처럼 만들어서 이용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Player {
	final String name;
	int age;
	String team;
	int number;
	Player({
		required this.name, 
		required this.age, 
		required this.team, 
		required this.number,
		});
	
	void sayName(){
	print("Hi my name is $name");
	}
}
void main(){
	var player = Player(
		name: "씅찬",
		age: 30,
		team: "red",
		number: 10,
	);
	var player2 = Player(name: "sseung",
	age: 30,
	team: "blue",
	number: 20,
	);
}

4.3 Named Constructors

콜론(:)을 사용하면 특별한 생성자 함수를 만들 수 있다.

콜론을 넣음으로써 dart에게 여기서 객체를 초기화하라고 명령할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Player {
	final String name;
	int age, number;
	String team;	
	
	Player({
		required this.name, 
		required this.age, 
		required this.team, 
		required this.number,
		});
		
		Player.createBluePlayer({ //named constructor
		required String name, 
		required int age
		}) : this.age = age,
				 this.name = name,
		 		 this.team = 'blue',
		   	 this.number = '1';
		
		Player.createRedPlayer(String name, int age) //positional
				: this.age = age,
					this.name = name,
					this.team = 'red',
					this.number = 11;
}

void main(){
	var player = Player.createBluePlayer(
		name: "씅찬",
		age: 30,
	);
	var redPlayer = Player.createRedPlayer("sseung", 30);
}

4.4 Named Constructors2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Player {
final String name;
int age;
String team;

Player.fromJson(Map<String, dynamic> playerJson) 
		:	name = playerJson['name'], // : 을 써서 property 초기화
			age = playerJson['age'],
			team = playerJson['team'];
void sayName(){
	print("Hi my name is $name");
	}
}
void main() {
	var apiData = [
	{
		"name": "씅찬",
		"team": "red",
		"number": 1,
	 },
	 {
		"name": "포엘",
		"team": "blue",
		"number": 1,
	 },
 ];
	
 	 apiData.forEach((playerJson) {
	 var player = Player.fromJson(playerJson);
	 player.sayHello(); 
 });
}

4.5 Cascade Notation

반복되는 부분 ‘sseung’을 ‘ .. ‘ 으로 대체할 수 있다.

앞에 class가 있다면 그 클래스를 가리킨다. 매우 유용한 operator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Player {
	String name;
	int age;
	String team;
}

Player({required this.name, required this.age, required this.team});

void main() {
	var sseung = Player(name: 'sseung', age: 30, team:'red');
	//sseung.name = '씅찬';
	//sseung.age = 29;
	//sseung.team = 'blue';
	..name = '씅찬'; //.은 sseung을 뜻함
	..age = 29;
	..team = 'blue';
	
}

4.6 Enums

enum은 우리가 실수하지 않도록 도와주는 타입이다.

Java Enum type과 동일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Team { red, blue }
enum Age {10, 20, 30 }

class Player {
	String name;
	Age age;
	Team team;
}

void main() {
	var sseung = Player(
		 name: 'sseung',
		 age: Age.30, 
		 team: Team.red);
	..name = '씅찬'; //.은 sseung을 뜻함
	..age = Age.20;
	..team = Team.blue;
}

4.7 Abstract Classes

추상화 클래스는 다른 클래스들이 직접 구현 해야하는 메소드들을 모아놓은 일종의 청사진이라 보면 된다.

추상 클래스에서는 기능을 구현하지 않는다.

Java와 동일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
abstract class Human {
	 void walk();
}

class Player extends Human {
	String name;
	Age age;
	Team team;
	
	void walk() {
		print('나는 걷습니다.');
}

class Coach extends Human {
	void walk() {
		print('코치는 걷습니다.');
}

4.8 Inheritance(상속)

상속을 하고 super를 이용해 부모 클래스의 생성자를 호출할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Human {
	final String name;
	Human({required this.name}); //required를 하게 된다면 18행 Player의 super에서
										// :name을 필요로 하게 된다.
	void sayHello() {
		print("Hi my name is $name");
	}
}

enum Team { blue, red }

class Player extends Human {
	final Team team;
	
	Player ({
		required this.team,
		required String name
	}) : super(name: name); //super를 통해 부모 클래스와 상호작용
	
	@override
	void sayHello() {
		super.sayHello();
		print("and I play for ${team}");
	}
}

void main() {
	var player = Player(
		team: Team.red,
		name: "씅찬",
	);
	
}

4.9 Mixins

Mixin은 생성자가 없는 클래스

Mixin 클래스를 상속할 때는 extends를 사용하지 않고 with를 사용한다

with한 클래스들의 parameter와 method를 사용한다

Mixin은 여러 클래스에서 재사용이 가능하다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Strong{
	final double strenghtLevel = 1500.99;
// 클래스일 뿐 어떠한 생성자도 가지고 있지 않다.
}

class QuickRunner{
void runQuick(){
print("ruuuuuu!");
	}
}

class Tall{
	final double height = 1.99;
}

enum Team { red, blue }

class Player with Strong, QuickRunner, Tall {
// Flutter나 Flutter 플러그인들을 사용할 때 with를 많이 접하게 된다.
	final Team team;

Player({
		required this.team,
		required String name,
	}); //super를 통해 부모 클래스와 상호작용할 수 있게 해줌.
}

class Horse with Strong, QuickRunner{

}

class Kid with QuickRunner{

}
// extend랑은 다르다
// -> extend를 하게 되면 확장한 그 클래스는 부모 클래스가 되고, 자식 클래스는 부모 클래스를
// super클래스를 통해서 접근이 가능하며, 그 순간 부모 클래스의 인스턴스가 된다.
// 하지만 Mixin은 with라는 키워드를 사용해서 역할은 단순히
// Mixin 내부의 프로퍼티와 메소드들을 가져오는 것 뿐이다.
void main() {
		var player = Player(
		team: Team.red,
		name: 'note',
	);
	player.runQuick();
}
This post is licensed under CC BY 4.0 by the author.

© sseung. Some rights reserved.