일기

Dart 공부하기_ 기본문법,OOP

o_b:us 2023. 1. 9. 22:39

서울에 면접보러갔다가 코로나에 걸려서 호되게 혼났다.
취준도 길어지고 하다보니 동기부여가 필요하다 생각되어 새롭게 프로젝트를 하나시작하려고 한다.

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시간만에 완전 정복

 

[무료] [코드팩토리] [입문] Dart 언어 4시간만에 완전정복 - 인프런 | 강의

이 강의를 통해 Dart 언어를 배우면 Flutter를 시작할 수 있을 정도의 수준으로의 업그레이드가 가능합니다!, - 강의 소개 | 인프런...

www.inflearn.com