서울에 면접보러갔다가 코로나에 걸려서 호되게 혼났다.
취준도 길어지고 하다보니 동기부여가 필요하다 생각되어 새롭게 프로젝트를 하나시작하려고 한다.
Flutter가 웹과 모바일 둘 다 사용이 가능하다하니 Flutter를 사용해보려고 한다.
우선 Flutter에 대해 하나도 몰라서 Dart라는 언어를 공부하면서 정리했다. 이번엔 작심삼일이 되지 않게 기록 좀 해야겠다.
아래는 Dart가 자바랑 비슷해서 그렇게 어렵게 느껴지진 않았다.
A.기본문법
void main() {
//출력
//변수 하나만 할떄는 {} 생략가능
//쌍따옴표도 가능
print('Hello Dart'); //Hello Dart
print('${name} $name2');
//정수 integer
int number1 = 1;
//실수 double
double number1 = 1.0;
//true/false
// boolean
bool isTrue = true;
bool isFalse = false;
// 글자 타입
// String
String name = '이름';
name = null; // (x) 불가
// var 동적 타입(런타임시에 타입 유추)
// 그렇다고 중간에 타입을 변경하는 것은 안된다.
var name = '이름';
name = 'asdf'; //변수 변경
name = 13; //(x) 불가
// dynamic 동적 타입
// 중간에 타입을 변경하는게 가능하ㅏㄷ.
dynamic name2 = '이름'
name2 = 10; //(o) 가능
// nullable
//타입에 ? 붙이면 null 가능 없으면 null 불가
String name = '이름';
name = null; // (x) 불가
String? name2 = '이름';
name2 = null; // (o) 가능
//! 현재 이 값은 null 이아니다
String name = '이름';
print(name!)// name이 null 일시에 runtime error
// final,const은 변수 앞에 선언
final String name = '이름';
const String name2 = '이름';
final name3 = '이름'; // final과 const는 타입 생략 가능(var)역할
const name4 = '이름';
//그렇다면 final과 const의 차이는?
//컴파일 시에 값이 있냐 없냐
//const는 컴파일 시에 값이 있어야하므로
//실행 시
final DateTime now = DateTime.now(); //(o) 가능
const DateTime now2 = DateTime.now(); //(x) 불가능
//연산자 대부분이 java랑 동일
//특이한 연산자 ??
//해당 변수가 null 이면 지정한 값으로 바꿔라.
int? number = null;
number ?? = 10;
print(number) //10;
//타입 확인 is, is!
int number = 10;
print(number is int);
print(number is String);
print(number is! bool);
}
//컬렉션
//다트는 배열을 제공하지 않음
//컬렉션 또한 var이나 dynamic으로 타입추론 가능
//var list = [1,2,3];
//List<dynamic> list = [1,2,3]; 등등
//List 메서드들도 자바랑 대부분 비슷함.
List<String> lists = ['가','나','다','라'];
List<int> lists2 = [1,2,3,4];
print(lists) // ['가','나','다','라']
print(lists2[0]) // [1] 제로베이스
//Map key/value
Map<String, int> dict = {
'치킨' : 1,
'김밥' : 2
}
dict.addAll({
'피자' : 3
});//추가하기
dict['새로운값'] = 4; //이런식으로도 추가 가능
print(dict['피자']); //3
//Set 중복은 제거
//메서드 대부분 자바랑 비슷
final Set<String> set = Set();
//if문
int number = 10;
if(number % 2 == 0) {
print('값이 짝수');
} else if(number % 3 == 0) {
print('값이 3의 배수입니다');
} else {
print('홀수 인 값 중의 3의 배수가 아닙니다');
}
//switch
int number = 3;
switch(number % 3) {
case 0:
print('나머지가 0입니다');
break;
case 1:
print('나머지가 1입니다.');
break;
default:
print('default'
break;
}
// for loop
//continue와 break도 java랑 같음.
for(int i = 0; i < 10; i++) {
print(i);
}
// for loop
int total = 0;
List<int> numbers = [1,2,3,4,5,6];
for(int i = 0; i < numbers.length; i++) {
total += numbers[i];
}
// enhanced for loop
for (int number in numbers) {
total += number;
}
//while loop
int total = 0;
while(total < 10) {
total += 1;
}
//enum
enum State{
ready,
go,
stop
}
State status = State.ready;
if(status == State.ready) {
}else if(status == State.go) {
}else{
}
// function - position parameter
void main() {
addNumbers(10,20,30);
}
addNumbers(int x, int y, int z){
print('함수 실행 = ${x+y+z}');
}
// function2 - optional parameter [] 사용
void main() {
addNumbers(10);//60
addNumbers(10,50,50);//110
}
addNumbers(int x, [int y = 20, int z = 30]) { // 기본값 넣기
int sum = x+y+z;
print(sum);
}
// function3 - named parameter {required} 사용
// optional과 같이 사용가능
void main() {
addNumbers(x: 10, y: 20);
addNumbers(y: 20, x: 10); // 같음 명시해놨기 때문에
addNumbers(x: 10, y: 30, z: 40);
}
addNumbers({required int x, required int y, int z = 30}) {
int sum = x+y+z;
print('x = $x ,y = $y');
}
//function4 - arrow function
int addNumbers(int x, {required int y, int z = 30}) => x+y+z;
/ *postion, named , optional 다 같이 혼용해서 사용 가능 */
//typedef
void main() {
Operation opertaion = add;
int result = operation(1,2,3);
print(result);//6
operation = subtract;
result = operation(1,2,3);
print(result);//-4
}
//반환값이 있는 함수
int printOne(){
return 1;
}
//심화 typedef 함수명= int Function();
void main() {
print(calculate(1,2,3,add));
print(calculate(1,2,3,subtract));
}
typedef Operations = 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, Operations operation) {
return operation(x,y,z);
}
B. 객체지향프로그래밍(OOP)
Dart의 모든 클래스는 Object를 상속하고 있다. → 자바와 마찬가지인 Object Oriented Programming
1. 클래스와 인스턴스 생성
//생성자로 인스턴스 생성하기
void main() {
//new 연산자 필요없음
Human human = Human('홍길동',['손','머리','발']);
print(human.name);
print(human.bodyList);
human.expressBody();
//named Constructor로 생성
Human human2 = Human.fromList(['이름',['body1','body2']]);
print(human2.bodyList);
}
class Human{
String name;
List<String> bodyList ;
//생성자 만드는법1 선언과 : 하단 콜론
// Human(String name, List<String> bodyList)
// : this.name = name,
// this.bodyList = bodyList;
//생성자 만드는법2 (간단함)
Human(this.name, this.bodyList);
//named Constructor
Human.fromList(List values)
: this.name = values[0],
this.bodyList = values[1];
void expressBody() {
print("${this.bodyList}");
}
}
2. 객체 불변화
//객체를 불변으로 만들어서 외부에서 수정이 안되게 하는게 중요하니까
//속성에 final 와 const 키워드를 붙이는 습관을 들이는게 좋다.
class Human{
final String name;
final List<String> bodyList;
const Human(this.name, this.bodyList);
...
}
void main() {
Human human = const Human('홍길동',['손','머리','발']);
}
3. getter/setter
void main() {
Human human = Human('홍길동',['손','머리','발']);
print(human.firstBody); // 손
human.firstBody = '얼굴';
print(human.firstBody); // 얼굴
}
class Human {
String name;
List<String> bodyList;
Human(this.name, this.bodyList);
//getter 타입 명시 없어도 되긴함
//Dart에서는 특이하게 get/set 키워드로 선언한다.
//기본적인 함수로 구현해도 되지만 명시적으로 나타내기 때문에 한눈에 알아보기 좋은것 같다.
String get firstBody{
return this.bodyList[0];
}
//사실 setter는 const/final 키워드를 쓰면서 객체 불변성을 지키기 위해 잘 쓰진 않는다.
set firstBody(String body) {
this.bodyList[0] = body;
}
}
4.private
dart에서는 private으로 할 경우 해당 파일에만 또는 해당 라이브러리에만 접근이 가능하다.
//java에서는 private 키워드로 썼지만 Dart에서는 _ 표시만 해주면 된
void main() {
_Human human = _Human('홍길동',['손','머리','발']);
print(human.firstBody); // 손
human.firstBody = '얼굴';
print(human.firstBody); // 얼굴
}
class _Human {
String name;
List<String> bodyList;
_Human(this.name, this.bodyList);
//getter 타입 명시 없어도 되긴함
String get firstBody{
return this.bodyList[0];
}
set firstBody(String body) {
this.bodyList[0] = body;
}
}
5. 상속(inheritance) : 단일상속만 지원
상속은 extends 키워드 사용 , 인터페이스는 implements 사용
자식생성자(필드1, 필드2) : super(필드1 : 필드1, 필드2 : 필드2);
child class is parent class ⇒ true
parent class is child class ⇒ false
void main() {
Human human = Human(name: "홍길동",age : 20);
human.printName();//홍길동
Warrior warrior = Warrior("전사",21);
warrior.printName(); // 전사
Human human2 = Warrior("직업",22); //
human2.printName();
}
class Human{
String name;
int age;
Human({required this.name, required this.age});
void printName(){
print('myname = $name');
}
}
class Warrior extends Human{
Warrior(String name,int age): super(
name : name,
age : age
);
}
6. 다형성(메서드 오버라이딩)
void main() {
TimesTwo tt = TimesTwo(2);
print(tt.calculate());//4
TimesFour tf = TimesFour(2);
print(tf.calculate());//8
TimesTwo tf = TimesFour(2); // 자바처럼
print(tf.calculate());//8
}
class TimesTwo {
final int number;
TimesTwo(this.number);
//method
int calculate() {
return number * 2;
}
}
class TimesFour extends TimesTwo {
TimesFour(
int number,
) : super(number);
@override
int calculate(){
return super.calculate() * 2;
}
}
7. static
java와 같은 역할
필등에 static 선언 시 클래스 자체의 필드에 영향을 받아서 모든 인스턴스에 영향을 줌.
메서드에 static 선언 시엔 인스턴스 생성없이 메서드 호출 가능
void main() {
Human human = Human("홍길동");
human.printNameAndJob();// 홍길동 null
Human human2 = Human("가나다");
human2.printNameAndJob();// 가나다 null
Human.job = "warrior";
Human.printJob();// warrior
}
class Human {
final String name;
static String? job;
Human(this.name);
void printNameAndJob() {
print('제 이름은 $name 이고 직업은 $job 입니다.');
}
static void printJob() {
print('Human의 직업은 $job입니다.');
}
}
8. 추상화
인터페이스와 abstract class는 implements 사용.
dart에서 인터페이스는 class로 나타낸다.
void main() {
Warrior warrior = Warrior("홍길동");
warrior.printName();//홍길동 입니다.
warrior.setName = "가나다";
warrior.printName();//가나다 입니다.
}
//interface
//다트에서는 interface 또한 class로 선언
class HumanInterface{
String name;
HumanInterface(this.name);
void printName(){} // {}대괄호까지 추가하고 세미콜론은 없이
set setName(String name) {}
}
class Warrior implements HumanInterface{
String name;
Warrior(this.name);
@override
void printName(){
print("$name 입니다.");
}
@override
set setName(String name){
this.name = name;
}
}
interface를 class로 사용하다보니 잘못하다 인스턴스 생성용으로 쓸 수 있다.
HumanInterface wrongClass = HumanInterface("이름"); 이럴 때 인스턴스화를 막기 위해 abstract를 활용하면 된다.
abstract class HumanInterface{
...
}
class Warrior implements HumanInterface{
...
}
9. 제네릭 - 타입을 외부에서 받을 때 사용
class Lecture<T,X> {
final T id;
final X name;
Lecture(this.id, this.name);
void printIdType(){
print(id.runtimeType);
}
}
void main() {
Lecture<String, String> lecture1 = Lecture('123','lecture1');
Lecture<int, String> lecture2 = Lecture(123,'lecture2');
}
출처 : 인프런_[코드팩토리][입문]Dart 언어 4시간만에 완전 정복
'일기' 카테고리의 다른 글
Flutter 설치하기 (0) | 2023.01.10 |
---|---|
Dart 공부하기_함수형프로그래밍, 비동기 (0) | 2023.01.10 |
"AI와 이야기하기: ChatGPT로 새로운 인공지능을 체험해보자" (3) | 2022.12.17 |
@Builder패턴 사용시에 nullpointException 고치기 (0) | 2022.08.01 |