Dart 차근차근_1주차

이안이다·2023년 9월 17일
0

Flutter

목록 보기
1/7

Dart 차근차근


자 세상 바쁜 2학년 2학기가 시작됐고, 이번 학기 TAB에서는 앱 개발의 기초를 스터디하기로 했다. Dart부터 시작해서 Flutter, 그리고 앱 런칭까지 해보는 것을 최종 목표로 한 학기의 팀 스터디를 시작하려 한다. 강의는 노마드 코더의 "Dart 시작하기" 를 통해 시작하기로 했고 총 4개의 세션으로 나누어 정리하려 한다.

한 학기간 함께할 우리 듬직한 팀장 희건이, 지민이, 미서 파이팅 !!


0. INTRODUCTION

이번에도 어김없이 니꼬쌤과 함께 저세상 텐션으로 시작하는 OT.
간단히 요약하자면, Flutter를 학습하기 이전에 왜 Dart를 학습해야하는지에 대한 Dart 선수학습의 중요성에 대해 강조한다. 진정한 객체지향 언어인 Dart! Lessss go~

Dart는 코틀린, 스위프트, 타입스크립트와 유사하다고 한다. 다행히 군대에서 타입스크립트에 대해 Do it!으로 조금 공부해 본 경험이 있으니 조금이나마 수월할 것 같다.

Why Dart

Dart를 쓰는 것만으로도 iOS, 안드로이드, 리눅스 등등 모두 접근할 수 있다고 한다.
다트는 모바일 개발에 최적화된 언어로써 특징이 하나 있는데, 바로 컴파일하는 방법이 개발 중일 때와 개발을 마치고 배포할 때 다르다는 점이다. 개발 중일 때는 화면에 바로바로 결과물을 보면서 피드백을 해야해서 JIT(just in time)컴파일러를 사용하지만, 개발을 마치고 배포할 때는 실제로 기계어로 번역되어서 작동하는 AOT(Agead of time) 컴파일러를 사용한다. 다른 언어들에서는 쉽게 찾아보기 힘든 특징이다. 이게 Dart가 개발하기에 또 배포하기에 특별하고 좋은 언어인 이유들 중 하나라고 한다.

플러터는 왜 Dart를 채택했을까?
앞서 설명했듯 Dart는 JIT, AOT 두 가지의 컴파일을 모두 지원한다. 모바일 개발에 아주 좋은 언어라는 뜻이다. 그리고 플러터와 다트는 모두 구글이 만들었다. 다른 언어들 예를들어 react-native, django, flask등 뭐든 간에 그들이 사용하는 언어를 수정할 수는 없다. 하지만 플러터와 다트는 한 회사에서 만들었기에 필요에 의해 서로 수정할 수도 있다고 한다. 사실 같은 회사에서 만들었다는 게 뭐 그렇게 중요한가?라고 생각했지만 니꼬의 설명을 들어보니 애법 중요할수도 ..... ? 리액트 쓰는 놈이 더 나은 효율을 위해 JS를 수정할 수 없고 Django 쓰는 놈이 더 나은 효율을 위해 Python을 수정할 수는 없지만!? Flutter 쓰는 놈은 더 나은 효율을 위해 Dart를 수정할 수가 있다는 것!


The way to Learn

https://dartpad.dev/?
앞으로 이 사이트를 통해서 온라인 개발환경에서 실습 및 연습을 진행할 수 있다고 한다. 최초 개발환경을 구축하기 위해 설치하고 뭐 설정하고 이러는 귀찮은 과정을 생략할 수 있어서 좋을 것 같으면서도 그래도 명색이 컴공학부생인데 벌써부터 가라치기를 좋아하면 안 될 것 같아서 VSCode에 flutter extension을 깔아서 앞으로 학습을 진행하도록 하겠다!

https://parkjh7764.tistory.com/171
위 사이트에 VS Code에 Flutter&Dart 익스텐션을 설치하고 기본 설정을 하는 방법이 잘 정리 되어 있다.

근데 뭐가 자꾸 안 된다 !! 당분간은 VS CODE 말고 그냥 다트패드에서 실습을 진행하여 코드를 벨로그에 기록하는 식으로 할랭....


1. VARIABLES

void main() {
  for (int i = 0; i < 5; i++) {
    print('hello ${i + 1}');
  }
}

dart 실습 시작해보자잉

main함수 필수 ! 세미콜론 필수 !

dart에서는 근데 일부러 세미콜론을 안 쓰는 경우도 있다고 한다.


Dart에서 세미콜론을 의도적으로 사용하지 않는 경우

1. 단일 표현식 블록

단일 표현식을 갖는 블록에서 세미콜론을 생략할 수 있다고 한다.

var x = 10
var y = 20

이렇게 간단한 표현식 블록에서는 생략할 수도 있다고 하는데 그냥 쓰는 습관 들이는 게 나을 것 같음...ㅎㅎ

2. 클래스 멤버 정의

클래스 내부에서 멤버 (메서드 또는 변수)를 정의할 때, 멤버들 간에 세미콜론을 사용하지 않는다고 한다. 예시 코드를 써보자면 아래와 같다 !

class IVE {
int x
String y
}

자 이런 경우에서 IVE라는 클래스 내부 멤버 정의에서 세미콜론을 생략했는데 처음에는 이해가 잘 안 갔다. '굳이?'라는 생각이 들어서 조금 더 알아봤더니 클래스 내부에서 변수를 정의할 때는 멤버들 간에 세미콜론을 쓰지 않는 것이 클래스 정의의 일부라고 한다. Dart만의 다른 언어들과 구별되는 특별한 문법 규칙 중 하나라고 한다. 어디까지나 클래스 내부에 해당하는 이야기고 클래스 외부에서는 일반적인 dart규칙을 따라야한다는 점 주의하자 !

3. 함수 리터럴 및 익명 함수

함수 리터럴 또는 익명 함수를 정의할 때, 함수 몸체가 단일 표현식인 경우에도 세미콜론을 생략할 수 있다고 한다.

var myFountion = (int a, int b) => a+b;

함수 몸체가 단일 표현식이므로 세미콜론을 사용하지 않았다. 1번과도 같은 맥락이다. 하지만 아직은 dart를 입문하는 단계인만큼 나중에 꼼꼼하게 정리하는거로 하고 일단 여까지만 이해하고 넘어가자!


1.1 ~ 1.3 (var ~ null safety)

variable의 약자인 var 타입은 함수 메소드 내부에 지역변수를 선언할 때 사용한다. JS를 공부할 때 익히 다뤄봐서 익숙하다. JS에서와 마찬가지로 dart에서도 var은 특정 타입이 정해져있지 않아서 flexible하다는 장점이 있다. 그치만 사용을 지양하자! 결국 유연한만큼 타입 안정성을 포기한다는 뜻이기 때문이다. 아직 강의에는 나오지 않았지만 dart에도 final과 const를 사용할 수 있다. 상수는 이렇게 쓰고 변수는 int면 int, string이면 string 이렇게 명시적으로 타입을 선언하는 방식을 지향하자!

var 타입의 변수에 문자열을넣었다고 하자. var은 정확히 어떤 타입이 될까? dynamic type이 된다. 명시적으로 타입을 dynamic이라고 지정할 수도 있다.

void main(){
	dynamic name;
}

이렇게 할 수도 있다. 지양하자면서 왜 dynamic타입을 강조할까? 나중에 앱을 개발할 때 인터넷에서 특정 data를 가져오는데 그게 어떤 형식인지 모를 때 dynamic타입을 사용하면 유용하기 때문이다. 이상적으로는 사용을 피하되, 필요할 때 사용할 수 있게 개념만 알아두자.

null safety에 대해 알아보자. 먼저 요약해서 설명하자면, dart에서 null safety란 어떤 변수 혹은 데이터가 null이 될 수 있음을 명시하는 것이다.
값이 null이 된다면 컴파일러는 런타임 에러를 낸다. 이걸 처리하기 위해 각 프로그래밍 언어마다 각각의 대책이 있는데 이건 dart의 대책인것! 코드로 이해해보자.

void main() {
  String myName="김이안";
  myName = null;
}

이렇게 하면 에러가 뜬다.

void main() {
  String? myName="김이안";
  myName = null;
}

근데 이렇게 하면 에러가 안 뜬다. 왜냐하면 dart는 이제 myName이 null이 될 수도 있다고 인지하기 때문이다. 따라서 내가 어떤 data를 담을 변수가 null이 될 수도 있고 안 될 수도 있다면 run time error를 방지하기 위해 변수타입에 물음표를 접미사로 사용함으로써 null이 될 수도 있다고 알려주는 것!


1.4 ~ 1.6 (final, late, const)

객프수업시간에 배우는 Java와 동일하게 final을 쓸 수 있다. 한 번 정의된 변수를 수정할 수 없게 만들려면 정적으로 고정시켜버리기 위해 쓰는 것. 너무 익숙한 내용이니 굳이 길게 정리하지 않겠음 !

final

JAVA의 final과 같음.

late

late는 final이나 var 앞에 붙일 수 있다.

void main() {
	late final String name;
    name = '이안';
}

late을 사용하면 변수를 먼저 만들고 데이터를 나중에 넣을 수 있게 해준다. 선언할 때부터 특정 값을 넣어줄 게 아니라, 나중에 데이터를 넣고싶을 때는 위와 같은 식으로 late를 활용하면 유용하다. 실제로 앱을 개발할 때 API로부터 데이터를 따와서 어느 변수에 저장해야할 때 미리 만들어놓는 저장공간 느낌으로 활용하면 좋다는 것!

const

다트에서의 const는 js나 type scriptd에서의 const와는 다르다.
다트에서의 const는 compile-time constant를 만들어 준다. const로 선언된 변수는 나중에 수정될 수 없다.

그렇다면 final과 const의 차이점은 뭘까?
final은 run time 중에 만들어진다는 거다. 사용자가 앱을 실행하면서 변수를 만들 수 있다는 뜻이다. 반면 const는 compile시간에 만들 수 있다.


2. DATA TYPES

String, boolean, integeer, double 등등 다양한 데이터 타입들이 있다.
이러한 모든 타입들은 객체이다. 하나하나의 타입이 모두 하나의 class라는 것!
JAVA에서 객체에 접근할 때는 클래스명.메소드명 이런식으로 접근하듯, dart도 마찬가지이고 다양한 메서드들과 데이터 타입들에 대해 배우는 챕터 !


2.1 ~ 2.3 (list ~ String Interpolation)

list

리스트는 일단 Int타입이다.

void main() {
  var numbers = [1,2,3,4, ]
}

뭐... 이렇게 리스트 맨 뒤에 쉼표로 끝내면 자동으로 줄바꿈 포맷팅 해준다던데 DartPad에서는 일단 안 된다.

String Interpolation

직역하면 문자열 보간법인데 이름과 달리 개념은 매우 쉽다. 예시 코드를 보자!

void main() {
  var name = 'ian';
  var age = 20;
  var greeting = "hi my name is $name, I'm ${age+2} years old";
  print(greeting);
}

}

자 이름이 담긴 변수와 인사하는 문장이 담긴 변수가 이렇게 있고, 인사하는 문장을 출력했다. $를 찍고 변수명을 쓰면 따로 형식지정자를 설정하거나 포맷팅을 하지 않아도 바로 아래와 같은 출력 결과를 확인할 수 있다. 그리고 나이 부분 처럼 계산하는 값을 넣고 싶으면 $찍고 중괄호 속에다가 계산식을 적으면 된다. 이게 바로 String Interpolation!

hi my name is ian, I'm 22 years old

Collection if, Collection for

이거 되게 유용함. if문과 for문을 굳이 따로 안 써도 한 줄로 간단하게 쓰게 해줌.
근데 약간 가라치는 것 같아서 나중에 dart가 익숙해진 후에나 다시 공부하고싶지 그 전까지는 정직하게 코딩하고 싶기에 이해만 하고 넘기겠음. ㅎㅎ


2.3 ~ 2.4 (Set)

Set

Set이라고 하는 놈이 있는데 list랑 비슷하다. 근데 얘는 모든 원소가 Unique하다는 특징이 있다. 예를들면,

이렇게 1을 네번이나 더했는데도 list라면 1이 다섯개로 늘었겠지만 Set에서는 그렇지 않다. 그리고 list와 달리 중괄호를 사용한다. 요소가 항상 하나씩만 있어야 되면 Set을 쓰면 되고, 아니면 그냥 list를 쓰면 된다. 요놈은 굉장히 유용할 것 같다.
아, 그리고 꼭 "Set"이런식으로는 선언하지 앟아도 된다. 그냥 var nums = {1,2,3,4}; 이렇게 해도 된다. 중요한 건 중괄호를 써서 Set을 쓰느냐 대괄호로 list를 쓰느냐이다. 파이썬에서의 tuple과 비슷하다.


3. Functions

3.0 ~ 3.2 (function, parameters)

String sayHello(String name){

  return "Hello $name nice to meet you";
}

int adding(int a, int b){
  int result = a+b;
  return result;
}

void main() {
  print(sayHello('ian'));
  print(adding(3,5));
}

예시 코드로 모든걸 설명할 수 있다. Nothing special !
void 함수는 String이나 int를 return할 수 없다는 거 주의 !


3.3 ~ 3.4 (QQ Operator)

Optional Positional Parameters

String sayHello(String name, int age, [String? country = 'Korea']) => 'Hello $name, you are $age yoears old from $country';

void main(){
var target = sayHello('ian', 12);
print(target);
}

자 지금까지 배운 내용들을 적절히 짬뽕해서 실습 코드를 만들었다. syntax가 조금 이상해 보일 수 있지만 null safety도 사용되었고, 화살표 함수도 사용되었다.

QQ Operator

자 내 이름을 대문자로 return해주는 함수 cap()을 만들어보자.

String cap(String? name) => name != null ? name.toUpeerCase()

void main(){
var a = cap('ian kim');
var b = cap('null');
print(a);
print(b);

}

자 일단 이렇게 cap이라는 함수를 만들었는데 인자에서 알 수 있듯이 name이 null이 될 수도 있기 떄문에 물음표를 통해 null safety를 적용하고자 했더니 Dart에서 그럴수는 없다고 난리를 친다. 왜냐하면 .toUpperCase()메소드를 null한테 적용할 수는 없기 때문이다. 그래서 if문을 사용해서 위와 같이 상황에 맞게 처리했다. if문은 이런식으로 사용하면 되는듯 하다.

자 이번에는 이 코드를 fat arrow를 활용해서 더 짧게 만들어보장.

String cap(String? name) => name != null ? name.toUpperCase() : 'ANON';

void main(){
var a = cap('ian kim');
var b = cap('null');
print(a);
print(b);

}

자 어떻게 이렇게 짧아진거냐면, QQ Operator이라는 개념 덕분인데,
left ?? right
이렇게 좌항과 우항이 있는데, 더블 물음표가 체크를 하는데 만약 좌항이 null이면 우항을 return해준다. 반대로 좌항이 null이 아니면 그대로 좌항을 return하는거다. 이걸 익숙하고 적절히 활용하면 이 예시처럼 코드를 간결하고 짧에 만들 수 있다.

추가로 찾아본 내용 두 가지

  1. QQ Operator는 정식 명칭이 아니며, 널 병합 연산자로서 (null coalescing operator)이라는 정식 명칭이 있다.

  2. 이렇게 간결하게 ?? 를 쓰는 것이 메모리 효율 측면에서도 과연 괜찮을지 궁금해서 찾아봤는데 결과부터 말하자면 똑같다고 한다. Dart 컴파일러와 실행 환경은 이러한 세부적인 차이를 최적화하므로 선택한 방법에 따른 성능 차이는 무시할 정도로 작다고 한다.


    3.5 Typedef

    이제 드디어 제대로 class에 대해 공부하나 싶었지만 니꼬쌤께서 그 전에 Typedef라는거까지만 설명하겠다고 하신다,, 자료형이 헷갈릴 때 도움이 될 alias를 만드는 방법이라고 한다. (alias = 별칭, 가명)

    함수를 하나 만들건데 숫자로 된 list를 반대로 뒤집어서 reverse버전으로 반환하는 함수다. 코드는 다음과 같다~~~!

List<int> reverseListOfNumbers(List<int> list) {
  var reversed = list.reversed;
  return reversed.toList();
}

void main(){
}

자 일단 이렇게 뼈대를 만들어놓고, typedef 써보면서 완성해보자.

typedef ListOfInts = List<int>;

List<int> reverseListOfNumbers(List<int> list) {
  var reversed = list.reversed;
  return reversed.toList();
}

void main(){
  print(reverseListOfNumbers([1,2,3,4,5]));
}

자 실행 결과는 [5, 4, 3, 2, 1]으로 잘 나오는 것을 확인할 수 있다.
typedef는 Dart에서 사용자 정의 타입을선언하는 데 사용된다. 앞서 말했듯 기존 타입에 대한 alias(별칭)을 만들 때 사용된다. 이렇게 별칭을 만드는 이유는 코드의 가독성을 향상시키고 타입을 더 명확하게 나타낼 수 있기 때문이다.

ListOfInts는 List와 같은 타입으로 간주되게 된다. 따라서 reverseLiseOfNumbers함수에서 List대신이 ListOfInts를 사용해서 코드를 작성할 수 있게 되는 것이다. 코드를 더 추상화하고 명확하게 만들 수 있는 방법 중에 하나인 듯 하다 !!!


여기까지가 Class를 본격적으로 배우기 전에 배워야할 1~3챕터이다.
2023-2 TAB App Team Study 1주차는 여기까지다!

앞으로도 주차별로 차근차근 정리해서 포스트하도록 하겠음. 고생했다 나 자신 ~~~

profile
경제와 개발을 곁들인 기획자..!

0개의 댓글