Dart 언어 공부 정리

원종인·2022년 6월 22일
2

Dart 공부

목록 보기
1/4

해당 공부는 유튜버 코드 팩토리의 수업 1시간만에 끝내는 Dart언어 기본기를 정리한 수업입니다.
중간에 다 적으려다가 너무 귀찮아서 그냥 기존에 몰랐던 부분들만 적으려고 합니다. 본인은 c언어를 하고 왔기 때문에 기본적인 c언어에서 나오는 부분은 제외하고 적을거니까 감안해주세요.
코드팩토리 - 1시간만에 끝내는 Dart언어 기본기

변수 선언하기

변수를 선언할 때에는 var를 사용해서 변수 선언을 해준다.
그러나 var는 해당 변수가 어떻게 사용되지 모를 때 사용해주는 것으로 기본적으로는 int처럼 직접 선언해주는 것이 좋다.

void main() {
  var name = "코드 팩토리";
  print(name);
}
<결과>
코드 팩토리

변수 타입

정수 int
실수 double
문자열 String
참거짓 bool
var은 변수를 사용할 때 해당 변수의 형태가 정해진다.

void main() {
  var name = "코드 팩토리";
  print(name);
}

해당 코드에서 name은 var로 선언되어 있지만 "코드 팩토리"라는 String값을 주었기 때문에 String으로 변경된다. 그리고 해당 변수 형태로 변경되면 다시 다른 변수 형태로 변경할 수는 없다.

void main() {
  String name = "레드벨벳";
  String name2 = "슬기";

  print("${name}, ${name2}");
  print("$name, $name2");
  print("${name.runtimeType}, ${name2.runtimeType}");
}

위의 코드처럼 변수를 print에 넣어줄 수 있다. 이때, $를 사용해야 하는데 ${}가 기본형태이고 {}은 생략할 수 있다. 그러나 객체를 사용할 때 '.'을 사용하게 되면 $가 '.'이전만 인식하기 때문에 오류가 발생한다. 그렇기에 {}으로 묶어서 사용하게 된다. 나는 그냥 {}으로 다 묶어버리는게 보기 편한 것 같다.

void main() {
  dynamic name = "레드벨벳";
  print(name);
  print(name.runtimeType);
  name = 3;
  print(name);
  print(name.runtimeType);
}
<결과>
레드벨벳
String
3
int

dynamic은 var과 동일하게 미리 변수의 형태가 정해지지 않는 것이다. 그러나 var과 다른 것이 있다면 var은 한번 형태가 정해지면 변경이 불가능하지만 dynamic은 다른 변수 형태로도 변경이 가능하다.

Nullable vs Non-nullable

void main() {
  String name = "코드팩토리";
  print(name);
  
  String? name2 = "블랙핑크";
  name2 = null;
  print(name2);
}
<결과>
코드팩토리
null

변수 형태 뒤에 ?을 사용하게 되면 해당 변수는 null을 사용할 수 있게 된다. 기본적으로 Dart는 null을 사용할 수 없게 하지만 ?을 붙이면 사용할 수 있다.

void main() {
  String? name2 = "블랙핑크";
  print(name2!);
}

이렇게 null이 들어갈 수 있는 즉 ?이 사용된 변수에 !을 사용할 수 있다. 해당 표시는 연산자에서 not을 의미하는 것이 아닌 해당 변수는 지금 null로 사용되고 있지 않다를 의미한다.

void main() {
  dynamic name = "레드벨벳";
  print(name);
  name = null;
  print(name);
  
  var name2 = null;
  print(name2);
}
<결과>
레드벨벳
null
null

참고로 dynamic으로 선언된 변수는 ?를 붙이지 않아도 null을 자유롭게 사용가능하다.
var을 사용하는 변수도 ?를 선언하지 않아도 null이 사용가능하다.

Final vs Const

final과 const로 선언하면 해당 변수를 선언한 이후 값을 변경할 수 없다.

void main() {
  final String name = "코드 팩토리";
  print(name);
  
  const String name2 = "블랙핑크";
  print(name2);
}
<결과>
코드 팩토리
블랙핑크

또한 final과 const로 선언한 변수는 변수타입 선언을 생략할 수 있다.

void main() {
  final name = "코드 팩토리";
  print(name);
  
  const name2 = "블랙핑크";
  print(name2);
}

final과 const는 DateTime을 사용할 때 차이를 알기 쉽다.
const는 빌드타입의 값을 알고 있어야 하고 final은 알지 못해도 된다. 그렇기에 DateTime의 경우 이를 사용하면 작동 이후에 시간이 측정 되기에 빌드타입이 만들어진 이후에 사용된다. 즉 const가 작동할 때에는 빌드 타입이 구축되지 않으므로 사용이 불가능하다는 뜻

void main() {
  final DateTime now = DateTime.now();
  const DateTime now = DateTime.now(); // 오류 발생
}

Operator 연산자

ex) 5 + 5 -> 10 + 더하기
ex) 5 - 5 -> 0 - 빼기
ex) 5 5 ->= 10 곱하기
ex) 5 / 5 -> 1 / 나누기
ex) 5 % 5 -> 0 % 나머지
ex) 5++ -> 6
ex) 5-- -> 4 참고로 ++5,--5도 가능
ex) 5 += 1 -> 6
ex) 5 -= 1 -> 4
ex) 5 *= 2 -> 10
ex) 6 /= 2 -> 3

??=는 해당 변수가 null일 경우 ??=뒤의 값으로 변경해주라는 뜻이다.

void main() {
  double? number = 4.0;
  print(number);
  
  number = null;
  print(number);
  
  number ??= 3.0;
  print(number);
}
<결과>
4
null
3

>,>=,<,<=,==,!=도 사용가능 이때에는 true,false로 결과가 나온다.

is를 사용하면 타입 비교도 가능하다.
is!를 쓰면 아닌지 물어보는 것

void main() {
  int number1 = 1;
  print(number1 is int);
  print(number1 is! double);
}

<결과>
true
false

and와 or로 조건을 여러개 연동 시킬 수 있다.
and는 &&, or는 ||를 사용하면 된다.

List

List를 사용할 때에는 generic을 사용하여 해당 리스트에 무슨 변수 형태가 들어가는지 정해주어야 한다.

void main() {
  List<String> blackPink = ["제니","지수"];
}

리스트에서 사용되는 기본 함수들

void main() {
  List<String> blackPink = ["제니","지수"];
  
  blackPink.add("코드팩토리");
  print(blackPink);
  
  blackPink.remove("지수");
  print(blackPink);
  
  print(blackPink.indexOf("제니"));
  
  print(blackPink.length);
}
 <결과>
[제니, 지수, 코드팩토리]
[제니, 코드팩토리]
0
2

Map

Map도 리스트와 유사하게 generic에서 key와 value의 형식을 지정해주어야 한다. 그리고 적어준다.

void main() {
  Map<String, String> dictonary = {
    "해리포터" : "해리해리",
    "론 위즐리" : "론론",
    "헤르미온느" : "헤르헤르",
  };
}

추가로 더 넣어주고 싶으면 addAll을 사용한다.

void main() {
  Map<String, String> dictonary = {
    "해리포터" : "해리해리",
    "론 위즐리" : "론론",
    "헤르미온느" : "헤르헤르",
  };
  print(dictonary);
  
  dictonary.addAll({
    "스파이더맨" : "스파스파",
    "아이언맨" : "아이아이",
    "헐크" : "헐헐"
  });
  print(dictonary);
}

<결과>
{해리포터: 해리해리, 론 위즐리: 론론, 헤르미온느: 헤르헤르}
{해리포터: 해리해리, 론 위즐리: 론론, 헤르미온느: 헤르헤르, 스파이더맨: 스파스파, 아이언맨: 아이아이, 헐크: 헐헐}

한개씩만 넣을 거면 이렇게 넣어도 된다.

  dictonary["헐크"] = "헐헐";
  
  <결과>
  {해리포터: 해리해리, 론 위즐리: 론론, 헤르미온느: 헤르헤르, 헐크: 헐헐}

key를 통해서 value를 찾을 수 있다. value를 통해서는 찾을 수 없다.

void main() {
  Map<String, String> dictonary = {
    "해리포터" : "해리해리",
    "론 위즐리" : "론론",
    "헤르미온느" : "헤르헤르",
  };
  
  print(dictonary["론 위즐리"]);
}

<결과>
론론

키를 통해 값도 바꿀 수 있다.

  Map<String, String> dictonary = {
    "해리포터" : "해리해리",
    "론 위즐리" : "론론",
    "헤르미온느" : "헤르헤르",
  };
  print(dictonary);
  
  dictonary["론 위즐리"] = "위즐위즐";
  print(dictonary);
}

<결과>
{해리포터: 해리해리, 론 위즐리: 론론, 헤르미온느: 헤르헤르}
{해리포터: 해리해리, 론 위즐리: 위즐위즐, 헤르미온느: 헤르헤르}

remove 키를 통해서 해당 키와 value를 지울 수 있다.

void main() {
  Map<String, String> dictonary = {
    "해리포터" : "해리해리",
    "론 위즐리" : "론론",
    "헤르미온느" : "헤르헤르",
  };
  print(dictonary);
  
  dictonary.remove("론 위즐리");
  print(dictonary);
}

<결과>
{해리포터: 해리해리, 론 위즐리: 론론, 헤르미온느: 헤르헤르}
{해리포터: 해리해리, 헤르미온느: 헤르헤르}

키와 value값만도 가져올 수 있다.

void main() {
  Map<String, String> dictonary = {
    "해리포터" : "해리해리",
    "론 위즐리" : "론론",
    "헤르미온느" : "헤르헤르",
  };
  
  print(dictonary.keys);
  print(dictonary.values);
}

Set

List는 중복된 값이 들어갈 수 있지만 Set은 중복된 값이 들어갈 수 없다.
기본적인 함수는 List와 거의 동일하다.
참고로 Set는 인덱스를 통한 값을 찾는 것이 불가능하다.

for문

for문에서 리스트를 활용한 해당 부분만 복습

void main() {
  List<int> numbers = [1,2,3,4,5];
  
  for(int number in numbers){
    print(number);
  }
}

<결과>
1
2
3
4
5

Enum

enum은 정확히 해당 값만 사용하겠다라는 것을 알리기 위해 혹은 오타가 발생하거나 실수할 경우 이를 빠르게 고치기 위하여 사용한다.

enum Status{
  approved,
  pending,
  rejected,
}

void main() {
  Status status = Status.approved;
  
  if(status == Status.approved) {
    print("승인입니다.");
  } else if(status == Status.pending) {
    print("대기입니다.");
  } else{
    print("거절입니다.");
  }
}

<결과>
승인입니다.

함수

기본적으로 함수는 positional parameter로 순서가 중요하다.
optional parameter - 있어도 되고 없어도 되는 파라미터
사용하지 않는 파라미터에 [] 대괄호를 넣으면 된다.
아래 코드는 실수로 인해서 오류가 발생한다. y랑 z가 사용 안해도 되는 변수가 되었지만 문제는 아무 값도 안들어가기에 null이 된다.
그렇지만 int만 사용하면 null값을 넣을 수 없으므로 int?로 쓰면 되지만 아래의 x+y+z에서 null을 더하게 되는 것이므로 또 오류가 발생한다.

void main() {
  addNumber(30);
}

addNumber(int x, [int y, int z]) {
  int sum = x + y + z;
}

이럴때에는 그냥 해당 파라미터 안에 쓰지 않는 변수에 값을 미리 정해주면 된다. 그러면 그 값이 고정적으로 설정되고 만약 함수를 사용하기 위해서 y나 z에 값을 넣어주게 되면 해당 값이 더 우선시 된다.

void main() {
  addNumber(30);
}

addNumber(int x, [int y = 30, int z = 40]) {
  int sum = x + y + z;
}
void main() {
  addNumber(30,40,50);	// 이러면 아래의 30,40이 아닌 40,50이 들어감
}

addNumber(int x, [int y = 30, int z = 40]) {
  int sum = x + y + z;
}

named parameter - 이름이 있는 파라미터, 순서가 중요하지 않다.
required를 사용하면 해당 변수는 이름을 지정해서 직접 선언해주라는 의미이다. 그렇기에 해당 함수를 사용한다면 변수:값 이렇게 선언해주어야 한다. 선언을 해주는 것이기에 순서는 상관없다.

void main() {
  addNumber(x:10, y:20, z:30);
  addNumber(y:20, x:10, z:30);
}

addNumber({
  required int x,
  required int y,
  required int z,
}) {
  int sum = x + y + z;
}

그리고 required를 무조건 사용해야 하는 것은 아니기에 required를 선언 안할 수 있다. 그렇게 되면 해당 괄호 안에서 사용되면 required가 선언되지 않은 변수는 optional이 된다. 그렇기에 오류 방지를 위해서 해당 변수에 값을 미리 설정해 준다.

void main() {
  addNumber(x:10, y:20,);
  addNumber(y:20, x:10, z:30);
}

addNumber({
  required int x,
  required int y,
  int z = 30,
}) {
  int sum = x + y + z;
}

그리고 해당 방식들을 다 섞어줘서 positional parameter랑 optional, named parameter를 다 사용하고 싶으면 아래 예시 처럼 된다.

void main() {
  addNumber(10, y:20,);
  addNumber(10, y:20, z:30);
}

addNumber(int x,{
  required int y,
  int z = 30,
}) {
  int sum = x + y + z;
}

arrowfunction은 화살표 함수로 함수를 더 편하게 사용하기 위한 코드이다. 위의 코드에서 return한 것과 동일한 코드가 된다.

void main() {
  addNumber(10, y:20,);
  addNumber(10, y:20, z:30);
}

int addNumber(int x,{
  required int y,
  int z = 30,
}) => x + y + z;

typedef

선언한 typedef와 사용되는 파라미터 변수가 모두 동일해야 한다.

void main() {
  Operation operation = add;
  int result = operation(10,20,30);
  
  operation = subtract;
  int result2 = operation(10,20,30);
}

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

int add(int x, int y, int z) => x + y + z;
int subtract(int x, int y, int z) => x - y - z;

현실적으로 위의 형태로는 사용하지 않고 다음 형태로 사용한다.

void main() {
  int result = calculate(30,40,50, add);
}

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

int add(int x, int y, int z) => x + y + z;
int subtract(int x, int y, int z) => x - y - z;

int calculate(int x, int y, int z,Operation operation) {
  return operation(x,y,z);
}

많이 나열하듯 작성한 거니 보기 힘들듯...

profile
아직 대학생입니다

0개의 댓글