Dart 입문

SHIN's avatar
Sep 26, 2024
Dart 입문
 

1. Dart 언어의 특징

💡
  • C#, JS, Java 등 어떤 언어든 숙지가 되어있다면 배우기 용이
  • Type 지원 언어, Type 추론도 지원
  • 단일 스레드로 비동기 방식 지원
  • UI에 최적화된 언어
  • 동시성을 지원하지만 완벽하게 격리됨(Isolate)을 보장
  • 스프레드 연산자 지원
  • 배열 x , Collection만 존재
 

2. Dart 기본

// 기본 개념 // static > heap > stack class Animal { int id = 1; static String name = "동물"; void speak() { // 메소드 (상태 확인 및 변경할때) } } String name = "Hello world"; void hello() { // main 전 생성 -> new 안해도 생성 // 메소드가 아니고 함수임 (기능을 가짐) int num = 10; // stack, heap=클래스가 있을 때. } void main() { print(name); print(Animal.name); Animal a = Animal(); print(a.id); }
 

3. Dart 변수

3-1. 변수
void main() { int n1 = 1; double d1 = 10.1; bool b1 = true; String s1 = "홍길동"; // print() 함수는 Console에 출력을 해주는 함수 // ${} 를 활용하면 문자열에 변수를 바인딩 가능 // stack은 열리지만 저장x print("정수 : ${n1}"); print("실수 : ${d1}"); print("부울 : ${b1}"); print("문자열 : ${s1}"); }
notion image
3-2. 타입 추론 (runtimeType)
  • var
void main() { var n1 = 1; // 타입 x, 단순 선언, stack 메모리 안 잡힘 var d1 = 10.1; var b1 = true; var s1 = "홍길동"; print("정수 : ${n1.runtimeType}"); print("실수 : ${d1.runtimeType}"); print("부울 : ${b1.runtimeType}"); print("문자열 : ${s1.runtimeType}"); }
notion image
  • dynamic
void main() { dynamic n1 = 1; print("정수 : ${n1.runtimeType}"); // dynamic 타입은 모든 타입을 받을 수 있고 다른 타입으로 변경 가능 n1 = 10.5; print("n1 : ${n1.runtimeType}"); }
 

4. 연산자

4-1. null 대체 연산자
String? username = null; // 전역 정적 메모리 (static) void main() { print(username); print(username ?? "임시아이디"); {
notion image
💡
  • 변수의 값이 null 이면 ?? 뒤의 값 출력, null 이 아니면 변수의 값 출력
 
 

5. 함수

int minus(int n1, int n2) { // (int n) => 매개 변수 // 타입 생략 가능 -> 타입 추론 : // overloading x return (n1 - n2); } Function f = (n1, n2) { // 익명 함수 return n1 - n2; }; Function f2 = (n1, n2) => n1 * n2; // 익명 함수 void main() { // minus(1,2) => 함수 호출 // (2) => 함수 호출시 전달하는 인수 int result = minus(1, 2); print(result); print(f(1, 2)); }
 
5-1. 익명함수
💡
  • 람다식 = return 키워드 안 적어도 값이 반환 (익명함수는 필요)
// 함수를 매개변수로 전달받을 땐 function 키워드 사용 void whenComeMother(Function beh) { beh(); // beh = 익명 } void main() { // 익명 함수를 인수로 전달 가능 whenComeMother(() { print("컴퓨터 끄기"); }); // 변수에 익명 함수 대입 가능 -> Function 타입 사용 Function add = (int n1, int n2) { print(n1 + n2); }; void main() { add(1, 3); } }
 

6. 클래스

// new keyword 생략 가능 class Cat { String name; int age; String color; int thirsty; Cat(this.name, this.age, this.color, this.thirsty); } class Dog { String name; int age; String color; int thirsty; Dog(String name, int age, String color, int thirsty) : // initialized (초기화) this.name = name, this.age = age, this.color = color, this.thirsty = thirsty; }
 
 

7. 상속 (Inheritance)

class Burger { String name; // 초기화는 밑 부분에서만 (생성자 or InitialLize에서만 초기화) Burger(String name) : this.name = name { print("버거 생성됨"); } } class CheeseBurger extends Burger { String name; CheeseBurger(this.name) : super(name) { print("치즈 버거 생성됨"); } } void main() { Burger b1 = CheeseBurger("치즈버거"); }
notion image
 
 

8. Mixin

  • 여러 클래스 계층에서 클래스의 코드 재사용
  • Mixin 사용 시 다중 상속 문제 해결, Composition을 사용하지 않고 다른 클래스의 코드 재사용 가능
// 데이터 물려받기 // 생성자(의존성) 주입 -> 물려받는건 한계 // is = 다형성 , has = composition mixin class Engine { int power = 5000; } mixin class Wheel { int count = 4; } // class Sonata { // Engine e; // Wheel w; // // Sonata(Engine e) // // : this.e = e; // 이거보단 (this.e) 가 더 간결 / 즉 뒤의 this.e를 () 안에 넣으면 깔끔 // // 이건 데이터 파싱 및 변경 시 사용 // Sonata(this.e, this.w); // } class Sonata with Engine, Wheel {} // has 하고 싶으면 with -> composition 코드 void main() { // Sonata s = Sonata(Engine(), Wheel()); // depandency injection Sonata s = Sonata(); // 인스턴스 생성 -> Engine, Wheel의 기능을 has-a 관계로 가짐 print(s.power); // Engine의 power 변수 출력 print(s.count); // Wheel의 count 변수 출력 }
💡
  • Sonata 클래스는 with 를 사용해 EngineWheel을 mixin으로 포함
  • Sonata = 다중 상속처럼 Engine, Wheel을 상속받는 것이 아닌, 이 클래스들의 기능을 composition 방식으로 가져옴
  • with 사용 시 SonataEngine, Wheel에 정의된 모든 변수와 메소드 사용 가능
 
정리
💡
  • mixin을 사용해 다중 상속처럼 여러 클래스 포함 가능
  • with = 클래스 간 composition 관계를 나타냄 → SonataEngine, Wheel 을 “갖고” 있는 것으로 간주
  • 의존성 주입을 사용하지 않고도 필요한 기능을 mixin으로 받아들일 수 있는 장점
 
 
 

9. Collection

9-1. List
// List = 데이터 중복 가능, 자료는 순차적으로 Index(번호)를 생성하여 쌓이게 됨 // 이때 <> 타입 사용 -> generic 타입 // ------------------------ List ---------------------------- // 타입 지정 List<int> nums = [1, 2, 3, 4]; // 초기화 // 타입 추론 var list = [1, 2, 3, 4]; final arr = [1, 2, 3, 4]; void main() { print(arr[0]); // 이거로 다 받을 수 있음 -> 주호쌤 print("========================="); List<int> nums = [1, 2, 3, 4]; // 교재 내용 print(nums[0]); print(nums[1]); print(nums[2]); print(nums[3]); }
notion image
 
9-2. Map
// Key & Value // List = imndex 번호로 값 찾음, Map = key로 찾음 Map<String, dynamic> session = {"id": 1, "username": "shin"}; void main() { session["model"] = "username"; // 외부에서 추가 시 "model" 형식으로. print(session["id"]); print(session["username"]); print(session["model"]); session.remove("id"); // 삭제 시 null print(session["id"]); }
notion image
 
9-3. Set
import 'dart:math'; void main() { Set<int> lotto = {}; // map과는 다르게 중복이 되지 않는 자료형 // Random 클래스는 dart:math 라이브러리를 사용합니다. Random r = Random(); lotto.add(r.nextInt(45) + 1); lotto.add(r.nextInt(45) + 1); lotto.add(r.nextInt(45) + 1); lotto.add(r.nextInt(45) + 1); lotto.add(r.nextInt(45) + 1); lotto.add(r.nextInt(45) + 1); print(lotto); // toList() 함수를 사용하면 List 타입으로 변경 가능합니다. List<int> lottoList = lotto.toList(); // List 타입은 sort() 메서드로 정렬할 수 있다. lottoList.sort(); print(lottoList); }
notion image
 

10. 반복문 (Stream)

10-1. map 함수
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = chobab .map((e) => e + "_간장") // 중간연산 .toList(); // 첫 e = 새우초밥 / map = iterate -> 순회하면서 return 함 => 수집 print(changeChobab); }
notion image
 
main 함수 사용 예제
💡
  • collection에 담긴 데이터를 반복해서 플러터 위젯에 담고 화면에 출력할 때 많이 사용 → for문 사용 하지 않는 이유 = for 문은 값을 return하지 못함
  • collection에 담긴 데이터를 반복해서 플러터 위젯에 담는데 그 값을 조금씩 변형해야 할 때 많이 사용
  • main 함수는 lterator 타입을 return 하기에 끝에 toList() 함수를 추가하여 list 타입으로 반환하는것이 좋음 (List 타입이 literator 타입보다 활용하기 좋음)
 
10-2. where 연산자
  • 조건 필터링 시 사용해서 collection에 담긴 데이터 삭제 시 많이 사용
void main() { // java에선 filter / boolean return 해야함 var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = chobab.where((e) => e == "새우초밥").toList(); var removeChobab = chobab.where((e) => e != "새우초밥").toList(); print(changeChobab); print(removeChobab); }
notion image
 
10-3. Spread 연산자 (Add)
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; // spread 연산자 -> collection 빼고 들어옴 ("새우초밥", "광어초밥", "연어초밥") -> 타입을 벗겨냄 = toList var changeChobab = [...chobab]; print(changeChobab); }
notion image
 

11. CRUD 정리

class Dog { int age; String name; Dog(this.age, this.name); @override String toString() { return 'Dog(age:$age,name:$name)'; } } void main() { // CRUD final list = [Dog(1, "토토"), Dog(2, "레르코"), Dog(3, "우유")]; // 1. 추가 var add = [...list, Dog(4, "누렁이")]; // 4, "누렁이" 추가 print(add); // 2. 수정 (age=1 이름을 토로토) var update = list.map((e) => e.age != 1 ? e : Dog(e.age, "토루토")).toList(); print(update); // 3. 삭제 (age=3) var del = list.where((e) => e.age != 3).toList(); print(del); }
 
 

최종 정리

// 주호쌤 실습 (type 종류) int n1 = 1; double n2 = 1.0; bool n3 = true; String n4 = ' "f", "1" ${n1}'; var n5 = 1; // 타입 추론 dynamic n6 = "값"; // obj 타입 // var? n6 = 3; -> 안됨 dynamic n8 = null; int? n9 = null; class Dog {} Dog d = Dog(); Dog? d2 = null; Function? f = null; Function f2 = () => 1; // 람다식 // Function f3 = () {}; // 익명 함수 final f3 = () {}; var f4 = () {}; int count = 1; // 앞에 final 붙임 = 상수라 못씀 / final쓰면 int(var) 생략 가능 void main() { count = 2; }
 
Share article

SHIN