[Flutter] flutter를 위한 dart #2

유지연·2024년 1월 19일
0

Flutter

목록 보기
2/2

👋 빠르게 dart 훑고가기!! (TIL 240120)

💡 dart의 데이터 타입

1. 기본적인 자료형

수많은 프로그래밍 언어와 마찬가지로 가장 대표적인 자료형은 아래와 같이 존재한다.

String name = "jiyeon";
int age = 22;
bool alive = true;
double credit = 3.333;

이 때 흥미로운 점은

- num?

dart에는 num이라는 자료형이 존재하는데, 이는 int와 double값을 모두 가질 수 있는 자료형이다. 또한 , num은 int와 double의 부모 class이다.

2. List

List는 Flutter에서 자주 쓰이는 자료형으로 [ ] 대괄호를 이용해 선언할 수 있다.
변수 선언과 마찬가지로 var를 이용해도 되고, List<자료형>처럼 type을 명시해줘도 된다.

var ages = [10, 17, 20, 5, 34];
List<int> ages = [10, 17, 20, 5, 34];

- collection if, collection for

dart는 List내에서 if, for 구문을 이용하여 리스트의 요소를 결정할 수 있는 유용한 문법인 collection if, collection for를 지원한다.

collection if

bool alive = true;
var ages = [10, 17, 20, if(alive) 5, 34];
// [10, 17, 20, 5, 34]

collection for

var favorite = ["math", "english"]
var subjects = [
	"korean",
    "science",
    for (var fav in favorite) "♥ $fav",
]

-string interpolation

text에 변수를 추가하기 위해서는 변수명 앞에 "$"를 붙여 사용하면 된다. 만약 연산이 수행되어야 하는 경우 $ 뒤에 { } 중괄호를 붙여 그 안에 연산식을 작성하면 된다.

var name = "jiyeon";
var greeting = "Hello $name";
var age = 22;
var introducing = "I\'m ${age - 2} years old.";

3. Map

js/ts의 object, python의 dictionary와 유사한 자료형으로 key와 value로 이루어져있다.
{ } 대괄호를 이용하여 선언하며, key와 value형의 자료형 제한은 없다.

var player = {
	"name": "jiyeon",
    "age": 22,
    "xp": 33.33333,
}

Map<int, bool> answer = {
	1: true,
    2: true,
    3: false,
}

key와 value를 가지는 구조로 object를 만들때 -> class

4. Set

List와 유사하나 Set의 원소는 중복될 수 없다는 특징을 가진다. { } 중괄호를 이용해 선언한다.
python의 tuple과 기능적으로 유사하다.

var ages = {10, 32, 22, 20 };
ages.add(10);
ages.add(10);
print(ages); // {10, 32, 22, 20}

💡 dart의 함수

1. Named paremeter

여러 개의 parameter를 가지는 함수를 작성하는 기본적인 방법은 아래와 같다.

String greeting(string name, int age, string country) {
	return "Hello $name, You're age is $age and you come from $country."
}

void main() {
	greeting(jiyeon, 22, Korea);
}

하지만 함수의 parameter를 넘겨줄 때 매번 순서를 기억하고 작성하는 것은 매우 번거롭다.
따라서 dart에서는 parameter에 이름을 부여해 순서를 고려하지 않고 이름에 맞는 변수값을 전달할 수 있도록 한다.

named parameter를 사용하기 위해서는 함수의 parameter를 { } 중괄호를 이용해 묶고, 함수를 호출할 때에는 "parameter의 이름 : 값" 형태로 전달해준다.

String greeting({string name, int age, string country}) {
	return "Hello $name, You're age is $age and you come from $country."
}

void main() {
	print(greeting(
    	country: "Korea",
        name: "jiyeon",
        age: 22,
    ));
}

- null safety!

위의 코드를 실행시키려고 하면 오류가 발생하는데 그 이유는 함수의 인자로 넘겨지는 값이 null이 될 수도 있기 때문이다. null값이 전달되는 것을 방지하기 위해 조치를 취해주어야 한다.

1) default value 설정하기

함수 호출시 null값이 전달되는 parameter가 있다면 설정된 default 값이 저장된다.

String greeting({string name="anon", int age=99, string country="none"}) {
	return "Hello $name, You're age is $age and you come from $country."
}

void main() {
	print(greeting(
    	country: "Korea",
        name: "jiyeon",
        age: 22,
    ));
}

2) required modifier 사용하기

함수의 parameter의 자료형 앞에 required를 붙여 반드시 값을 가져야함을 명시해준다.
required를 사용하게 되면 함수 호출시 값이 없는 인자가 있다면 컴파일 되지 않는다.

String greeting({required String name, required int age,required String country}) {
	return "Hello $name, You're age is $age and you come from $country."
}

void main() {
	print(greeting()); //error!
}

- Optional Positional Parameter

필수로 전달되지 않아도 되는 parameter를 설정할 때는 [ ] 대괄호 안에 자료형? 변수명 = default 값 으로 작성한다.

String greeting({String name, int age, [String? country = "none"]}) {
	return "Hello $name, You're age is $age and you come from $country."
}

2. QQ operator : ??, ??=

?? 연산자를 기준으로 왼쪽에 있는 값이 null이면 오른쪽 값을 return 한다.

String capitalizeName(String? name) => name?.toUpperCase() ?? "ANON";

??= 연산자를 기준으로 왼쪽에 있는 변수의 값이 null이면 오른쪽 값을 할당해준다.

String? name;
name ??= "anon";

3. typedef

복잡한 자료형의 alias를 만들어줄 수 있다. (단, 구조화된 data의 형태를 사용하고 싶다면 class가 더 적절)

typedef UserInfo = Map<String, String>

💡 dart의 class

1. class의 구조

class의 property를 정의할 때는 자료형을 명시해줘야한다. 변수의 modifier를 이용하여 값의 변경을 막을 수 있다. → final String name = "jiyeon"
또한 class 내부에서는 this를 쓰지 않는 것이 권고된다. (변수와 class property의 이름이 같지 않은 이상!)

class Player {
	String name = "jiyeon";
    int hp = 100;
    
    void sayHello() {
    	print("Hi my name is $name");
	}
}	

void main() {
	//인스턴스 생성
	var player1 = Player();
    //인스턴스에 접근하여 property값 수정
    player1.name = "yeonji";
}

- 생성자 Constructor

생성자 함수의 이름은 class명과 동일해야한다.
class property의 값을 생성자에서 처음 할당해줄 것이라면 변수 선언시 late를 붙여야 한다.

class Player {
	late final String name;
    late int hp;
    
    Player(String name, int hp) {
    	this.name = name;
        this.hp = hp;
    }
}	

void main() {
	//인스턴스 생성
	var player1 = Player("namoo", 524);
}

생성자 함수의 인자 부분에서 바로 property값을 저장하도록 만들 수도 있다.

class Player {
	final String name;
    int hp;
    
    Player(this.name, this.hp);
}

- Named Constructor Parameter

위의 함수 부분과 마찬가지로 parameter의 개수가 많아지는 경우, named parameter를 이용해 코드를 보다 깔끔하고 명료하게 작성할 수 있다. 방법은 위와 동일하다! (null safety 주의)

class Player {
	final String name;
    int hp, level;
    String sex;
    
    Player({
    	required this.name,
        required this.hp,
        required this.sex,
        required this.level,
   });
    
}	

void main() {
	//인스턴스 생성
	var player1 = Player(name: "jiyeon", sex: "F", level: 100, hp: 378);
}

- Named Constructor

기본적인 생성자 메소드와는 다르게 따로 생성자 함수를 작성해줄 수도 있다.
class명.생성자함수이름() : 로 사용하며 콜론 ":"을 사용하는 특징이 있다. 이를 통해 class 객체를 초기화해주는 생성자 함수를 만들 수 있다.

Player.createF({
	required String name,
    required int age,
}) : this.sex = "F",
	 this.hp = 0;
     
Player.createM({
	required String name,
    required int age,
}) : this.sex = "M",
	 this.hp = 0;
     
var playerF = Player.createF(name: "jiyeon", age: 22);
var playerM = player.createM(name: "namoo", age: 26);

- cascade notation

class의 object를 생성하고 해당 object의 property나 method를 연속적으로 이용하는 경우, object의 이름을 생략할 수 있게 해주는 문법이다. 이를 사용하기 위해서는 object를 생성할 때 세미콜론을 생략해줘야 하며 ..을 사용하는 가장 마지막 line에만 세미콜론을 붙인다.

void main() {
	var jiyeon = Player(name: "jiyeon", sex: "F", level: 100, hp: 378)
    ..sex = "M"
    ..level += 1
    ..sayHello();
}
void main() {
	var jiyeon = Player(name: "jiyeon", sex: "F", level: 100, hp: 378);
    jiyeon.sex = "M";
    jiyeon.level += 1;
    jiyeon.sayHello();
}

위의 두 코드는 동일한 작업을 수행한다.

2. Enum

enum은 상수 열거형이라고 하며, 특정 상황에서 쓰이는 것들을 묶어놓은 개념이라고 할 수 있다. C의 define과 유사하다. enum 내부에 쓰인 상수는 자동으로 0,1,2... 와 같은 상수가 매핑된다.
enum변수명.요소로 접근하여 사용할 수 있다.

enum Sex = {F, M}

class Player {
	final String name;
    int hp,level;
    Sex sex;
    
    Player({
    	required this.name,
        required this.hp,
        required this.sex,
        required this.level,
   });
    
}

void main() {
	var jiyeon = Player(name: "jiyeon", sex: Sex.F, level: 100, hp: 378);
}

3. Abstract Classes 추상 클래스

추상 클래스는 인스턴스화 할 수 없는 class로, 다른 class에게 공통된 특징과 동작을 정의하는데 사용된다.

abstract class Human {
	//abstract method 추상메소드
	void walk();
}

추상 클래스는 추상 메소드를 가지며 이 메소드는 반환타입, 이름, 매개변수만을 정의한다. 메소드의 실제 구현은 해당 추상 클래스를 상속받는 하위 class에서 해야한다.

class Coach extends Human {
	void walk() {
    	print("I'm walking");
	}
}

추상 클래스는 다른 클래스들 사이에 공통된 동작을 추상화하는 데 유용하다. 또한 추상 메소드를 통해 하위 클래스에서 특정 동작의 구현을 강제할 수 있으므로, 다형성코드 재사용성을 높일 수 있다.

4. Inheritance 상속

super라는 키워드를 통해 부모 클래스와 상호작용할 수 있게 해준다. 아래 코드는 Player 클래스가 Human 클래스를 상속받는 예시이다. Player에서 생성자가 호출될 때 부모 class인 Human의 생성자도 호출되어야 하는데 이를 연결해주는 것이 super이다.

class Human {
  final String name;
  Human(this.name);
  void sayHello() {
    print("Hello My name is $name");
  }
} 

enum Team{red, blue, yellow}

class Player extends Human {
  final Team team;
  Player({
    required this.team,
    required String name,
  }) : super(name);
}

void main(){
  var player1 = Player(team: Team.red, name: "jiyeon");
  player1.sayHello();
}

5. Mixin

Mixin은 생성자가 없는 class를 말한다. 다른 class의 property와 method를 끌어오는 역할을 하며 with 키워드를 사용해 작성할 수 있다.

mixin class Strong {
  final double power = 9999.999;
}

enum Team{red, blue, yellow}

class Player with Strong {
  final Team team;
  final String name;
  Player({
    required this.team,
    required this.name,
  });
}

void main(){
  var player1 = Player(team: Team.red, name: "jiyeon");
}
profile
Keep At It

0개의 댓글