[Flutter] 4 Dart 문법 (2)

문법(1)에 이어서...
김호정's avatar
Sep 27, 2024
[Flutter] 4 Dart 문법 (2)
 
지난번에 null safety 까지 했으니
 
교재 64쪽 상속부터 하자
 

4-1 상속

 
notion image
 
notion image
 
버거 생성됨
치즈 버거 생성됨
 
⇒ 부모 먼저 실행되고 자식 실행됨
 
notion image
 
자바는 이렇게 super ( 자식이 부모의 객체를 참조할 수 있는 키워드 )가 생략되어져 있는데,
super가 먼저 실행되니 부모 print 먼저 실행되고 밑에 자식의 print가 실행됨
 
notion image
 
다트는 이렇게 super를 사용하는데 되어있는데 super가 생략되어 있음
 
→ 부모 먼저 때리고 자식 실행 !
 
: 는 이니셜 라이져 → 생성자의 내부 스택이 실행되기 전에 다른 무언가를 호출하고 싶을 때 사용
 
 
 
notion image
 
이렇게 초기화는 할 수 있지만
 
notion image
 
이렇게는 안됨
 
notion image
 
이렇게 초기화 해야함.
 
() 안에서 초기화 할 수는 있지만
{} 중괄호 안에서 this.name 해서 초기화 할 수는 없음
notion image
 
생성자를 때리면 initialized 키워드( : 뒤에 부분 ) 에서
초기화 해야한다.
 
 
notion image
 
이렇게 : 뒤에서 초기화 되던가
() 안에서 초기화 해야한다.
중괄호 안에서 할 수는 없다.
 

ex11.dart

class Burger { String? name; Burger(String name) : this.name = name { this.name = name; print("버거 생성됨"); // 접근 제어자 그런거 없음 } } class CheeseBurger extends Burger { String name; CheeseBurger(this.name) : super() { print("치즈 버거 생성됨"); } } void main() { Burger b1 = CheeseBurger(); }
 
이상한데? 뭔가 잘못 쓴듯.
 
class Burger { String? name; Burger(String name) : this.name = name { print("버거 생성됨"); print(name); // 접근 제어자 그런거 없음 } } class CheeseBurger extends Burger { CheeseBurger(String name) : super(name) { print("치즈 버거 생성됨"); } } void main() { Burger b1 = CheeseBurger("버거버거"); }
 
이렇게 하니까 된다
 
pdf 버전
 
class Burger { final String name; Burger(this.name); } class CheeseBurger extends Burger { CheeseBurger(String name) : super(name) { } } void main(){ CheeseBurger cb = CheeseBurger("치즈햄버거"); print(cb.name);
 
notion image
 
추상 매서드로 만들면 구현 안했다고 에러 내줌 (good)
 
notion image
 
다형성 으로 멍멍이 실행된다.
 

p. 68

컴포지션 ⇒ Mixin 을 사용하자 !

 
데이터를 물려받을 때는 컴포지션을 한다.
 
상속이 아니라 의존성 주입을 한다.
 
상속으로는 물려받는데 한계가 있다.
 
다중 상속 안되어서 1개만 상속 받을 수 있다는 단점이 있다.
 
그래서 물려받을 때는 의존성 주입을 한다. (DI)
 
상속은 다형성, 동적바인딩 이런 용도로 사용한다.
 
 
소나타는 엔진 ? no → has → 컴포지션 (소유, 포함)
소나타와 자동차 ? yes → is → 다형성 관계 (동등)
 
has → 컴포지션
is → 다형성
 
notion image
notion image
 
이렇게 길게 쓰지말고 this.e (위에꺼) 로 써라.
→ 아래꺼는 한줄로 뭔가 변경해야할때만 쓰기. (어제배움)
 
notion image
 
Engine 말고 Wheel 도 하려면 ?
1개 더 하려면 , 해서 넣어준다.
 
휠과 소나타도 컴포지션 ! (has)
 
notion image
 
우리가 스프링에서 이렇게 의존성 주입을 해서 썼다. ( 소나타의 생성자에 들어가서 생성됨 )
 
이제 컴포지션 코드는 지우고 !
 
아래처럼 사용하자
 
더 간단한 방법이 있다.
 
notion image
 
상태를 초기화 하는 것을
 
컴포지션하지말고 with 을 사용해서 해라!
 
notion image
 
잘된다. → 의존성 주입 !!!!
 
has 관계는 mixin 으로 사용하기 !
 
이미 만들어진게 mixin으로 만들어져 있으면 with 써라 !
 
→ mixin은 컴포지션 코드 !
 

ex12.dart

mixin class Engine { int power = 5000; } mixin class Wheel { int count = 4; } class Sonata with Engine, Wheel {} void main() { Sonata s = Sonata(); // 의존성 주입 (DI) print(s.power); print(s.count); }
 

p. 73

컬렉션

 
notion image
 
for 반복문 사용할 때 : 대신에 in 을 사용한다.
 
notion image
notion image
notion image
 
자바도 var 된다.
 
자바 17부터
 
var b = new Board(); 이렇게 받을 수 있다.
 
 
notion image
 
그냥 int는 값 변경 가능
 
notion image
 
final → 읽기 전용이라 변경이 안됨 ( 그래서 main 에 에러가 난다 )
 
const도 있는데 나중에 배운다.
notion image
 
final 을 쓰면 int 는 안쓴다.
 
final 뒤에 타입을 안쓰면 var이 생략된 것 !
 
 
notion image
 
final은 이렇게도 쓸 수 있다.
 

쌤이 준거

int n1 = 1; double n2 = 1.0; bool n3 = true; String n4 = '"f","1" ${n1}'; var n5 = 1; // 타입추론 dynamic n6 = "값"; // 오브젝트 타입 var n7 = null; dynamic n8 = null; int? n9 = null; class Dog{} Dog d = Dog(); Dog? d2 = null; Function? f = null; Function f2 = ()=>1; final f3 = (){}; var f4 = (){}; final count = 1; void main(){ }
 

내가 쓴거 ex13.dart

int n1 = 1; double n2 = 1.0; bool n3 = true; String n4 = '"f", "1" ${n1}'; dynamic n5 = 1; // 타입추론 var n9 = 1; // 타입추론 dynamic n10 = "값"; // 오브젝트 타입 //var? n6 = 3; // var에는 ? 못붙인다. (에러) var n7 = null; // var은 모든 타입을 받으니 null 이 ㄷ르어간다. dynamic n15 = null; int? n99 = null; class Dog {} Dog d = Dog(); Dog? d2 = null; Function? f = null; Function g2 = () => 1; final f3 = () {}; // 함수를 var에 받을 수 있어서 var에 적는다. // Function 으로 받지말고 var로 받기 final count = 1; void main() { count = 2; }
 
 

컬렉션

 
 
 
 
notion image
 
arr이라는 열쇠. 주소는 시작하는 데이터의 주소만 가지고 있으니
final로 써도 된다.
그리고 데이터가 바뀔수도 있다.
 
notion image
 

ex14.dart

List<int> nums = []; // 초기화 List<int> nums2 = [1, 2, 3, 4]; // 이렇게도 가능 var list = [1, 2, 3, 4]; // 이게 더 편함 . 이렇게 쓰기 final arr = [1, 2, 3, 4]; // 이렇게 젤 많이 쓴다. void main() { print(arr[0]); }
 
++
타입은 통신할 때 엄청 중요하다.
 
DTO는 타입 다 적기 !!!!
 
정의만 해둘거면 타입 적기 !
List<int> list; 이렇게
 
타입이 잘 되어 있어야지 런타임 실행할 때 에러가 안난다.
 

Map

 
notion image
 
외부에서 추가하려면 session[] 이렇게 추가해야하고
 
위에서 Map에서 추가하려면 “” 해서 넣어주면 된다.
 
 
notion image
 
 
다 출력 된다 : )
 
notion image
 
문법이 엄청 많은데 스트림으로 하면 다루기 쉬워진다.
 
위처럼 remove를 써도 되는데
 
삭제하는것도 스트림으로 하면 된다.
 
 
 
 

Set

 
중복이 되지 않는 자료형
 
→ 로또 만들어 보자
 
import 'dart:math'; void main() { Set<int> lotto = {}; // 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
 
중복 안되었을 때 !
 
 
notion image
 
중복되면 결과가 줄어서 나온다.
 
while 돌려서 크기가 6될때까지 돌리면 된다.
 

반복문 + 삭제

p. 74쪽
 
보통 for 문을 쓴는데 Stream이 훨씬 좋다.
 
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; // chobab[0] = chobab[0]+"_간장"; // chobab[1] = chobab[1]+"_간장"; // chobab[2] = chobab[2]+"_간장"; for (var i = 0; i < chobab.length; i++) { chobab[i] = chobab[i] + "_간장"; } print(chobab); }
 
이건 for문 쓴거
 
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = chobab.map((e) => e + "_간장").toList(); print(changeChobab); }
 
List ⇒ 새, 광, 연
 
map 을 쓰는 순간
 
새우초밥의 타입이 벗겨짐
 
 
iterator 자료형
 
컬렉션의 젤 부모 자료형
 
-> 이터레이터는 0, 1, 2, 3 번지 이렇게 순차적으로 찾아감
 
notion image
익명함수와 람다식 둘 다 뜬다. 둘 다 사용할 수 있다.
 
익명함수 써도 되지만
 
람다식 쓰면 한줄로 쓸 수 있음
 
notion image
 
실행해보면
 
notion image
 
 
map은 iterator 임
 
내부에서 순회하면서
 
물가에 있는 애 e ( ← 타입이 벗겨져서 물가에 던져진 녀석들 )
 
에 “_간장” 을 뿌리고 (map은 내부에서 “가공”하는것. “중간연산”이라고 함 )
 
toList로 “수집”
 
 
→ 새우초밥일 때는 간장을 안뿌리고 싶으면 이렇게
 
notion image
 
 
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = chobab.map((e) { if (e == "새우초밥") { return e; } else { return e + "_간장"; } }).toList(); print(changeChobab); }
 
 
 
map은 다 던지는데 가공을 하냐안하냐의 차이
 
where을 쓰면
 
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = chobab.where((e) => e == "새우초밥").toList(); print(changeChobab); }
notion image
 
true 만 수집해서 뿌린다.
 
 
 
언제 쓰냐
 
 
  1. 삭제할 때
  1. 검색할 때
 
 
새우초밥을 검색할 때는 이렇게 검색하면 되는데
 
notion image
 
삭제하고 싶을 때는 removeChobab 처럼 써라
 
 
왜 스트림을 써서 삭제해야하는가? chobab.remove 해서 간단하게 remove 하면 안되냐 ?
 
 
map이랑 where은 깊은 복사를 해서 새로운 자료형을 만들어 낸다
 
flutter는 상태관리를 하는데
 
화면에 그림을 다시 그릴때
 
변경된것만 그림을 다시 그림
 
원 데이터 chobab이 불변이어야 한다.
 
changeChobab 하면 화면에 새우초밥만 남고 다 사라진다. ( 데이터가 초기화 된다 )
 
removeChobab 하면 광어초밥, 연어초밥만 남는다. ( 삭제 )
 
 
 
 
기존 데이터가 없으면 컴퓨터가 뭐가 있는지 모른다.
 
기존 데이터가 있어야 데이터가 달라졌는지 알 수 있다 컴퓨터는. 사람과 다르다.
 
데이터가 왔다고 무조건 그려주는게 아니라
 
상태가 바뀌었을 때 그림을 다시 그린다!
 
 
변경 되지 않았으면 안 그린다.
 
상태가 바뀐 걸 알려면 뭐가 있어야 함 ? ⇒ 원데이터!
 
그래서 원데이터에서 remove 하지 말라는 것임 !!!!
 
 
내부 엔진한테 원데이터(불변데이터) 하나 주고 변경된 데이터를 주면
 
자기가 판단해서 변경되었으면 reload 하거나 변경 안되었으면 reload 안함
 
 
 
 
그래서 map 과 where을 쓴다..
 
 
 
notion image
 
이렇게 쓰지마라.
 
→ 원데이터가 달라지게 하지마라 ! (원데이터 = chobab)
 
 
 
++
 
map 가공
 
where 깊은복사
 
 
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = chobab.where((e) => e == "새우초밥").toList(); var removeChobab = chobab.where((e) => e != "새우초밥").toList(); print(changeChobab); print(removeChobab); }
 
 

추가

notion image
 
… 은 흩뿌리는 연산자
 
물길에 뿌린다는 뜻
 
타입을 벗김
 
 
notion image
 
 
이렇게 생겼다는 거임
 
notion image
 
 
추가할 때는 이렇게 추가한다.
 
notion image
 
잘 추가 되었다.
 
중간에 추가하는건 좀 복잡하다..
 
void main() { var chobab = ["새우초밥", "광어초밥", "연어초밥"]; var changeChobab = [...chobab, "장어초밥"]; print(changeChobab); }

컬렉션에 Object를 넣어서 하는 방법

 
지금은 기본 자료형을 쓰는 중인데 Object 를 넣어보자
 
 
notion image
 
hello 라는 이름을 생성자에 붙여줌 → “이름이 있는 생성자”
 
생성자에 이름을 붙여서 추가적으로 생성할 수 있음
 
notion image
 
맵을 받아서 초기화를 할려면
 
초기화를 해줘야 함
 
 
 
 
 
Map은 json이랑 똑같이 생김 그냥 앞에 쌍따옴표가 없음
 
 
json요청을 했을 때
 
자바에서는 DTO 만들어서 받아야하는데
 
여기에서는 MAP으로 받을 수 있다. (완전 편리)
 
그래서
 
notion image
 
이렇게 바로 깊은 복사하면 된다.
 
 
json array 는 맵이 아니니까 dynamic 으로 받으면 된다. ( 나중에 해볼 것임 )
 
class User { int id; String username; String password; User(this.id, this.username, this.password); User.hello( {required this.id, required this.username, required this.password}); User.fromJson(Map<String, dynamic> json) : this.id = json["id"], // map 이니까 이렇게 써준다 this.username = json["username"], this.password = json["password"]; } void main() { User u1 = User(1, "ssar", "1234"); User u2 = User.hello(id: 1, username: "ssar", password: "1234"); User u3 = User.fromJson({"id": 1, "username": "ssar", "password": "1234"}); print(u1.username); print(u2.username); print(u3.username); }
notion image
 
이름있는 생성자 는 이렇게 쓴다.
 
 
단점은 static인지 이름있는 생성자인지 . 해서 쓸때 헷갈릴 수 있다는 것 ?
 
class User { int id; String username; String password; User(this.id, this.username, this.password); User.hello({required this.id, required this.username, required this.password}); User.fromJson(Map<String, dynamic> json) : this.id = json["id"], this.username = json["username"], this.password = json["password"] ; } void main(){ User u1 = User(1, "ssar", "1234"); User u2 = User.hello(id: 1, username: "ssar", password: "1234"); User u3 = User.fromJson({ "id":1, "username":"ssar", "password":"1234" }); print(u1); print(u2); print(u3); }
 
 
 
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); }
 

내가 푼 것 (ex21.dart)

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, "우유") ]; // 수정하지 말라고 final 붙여둠 // 1. 추가 var add = [...list, Dog(4, "누렁이")]; // 4, 누렁이 추가 print(add); // 2. 수정 (age가 1번인 아이의 이름을 토루토로 변경) // var update = list.map((e) { // if (e.age == 1) { // e.name = "토루토"; // return e; // } // }).toList(); 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); // 4. 출력 (깊은 복사) var select = [...list]; print(select); }
 
notion image
 
이렇게 나온다.
 
수정 뭐임 ?
 
notion image
 
1이 아니면 e 반환
1이면 토루토 Dog 반환이군
 
이해하기
 
 
 
 
 
 
 
++
전개연산자 ?
 
 
++
커서 ai 설치 ?
 
 
++
MVVM 패턴
 
 
 
 
 
 
 

비동기 ( 부분만 바꾸는거 → 플러터 하면서 나중에 배울 것임 )

Share article

keepgoing