Dart 문법 공부

juhno1023·2024년 7월 4일
0
post-thumbnail

1. 변수

var name = '변수 값'; // 1
String name = '변수 값'; // 2
final name = '변수 값' // 3
late final String name; // 4
const a = 6; // 5

1) 변수의 타입을 구체화 할 필요 없다. Dart 컴파일러가 변수의 타입을 추측해서 알아낸다.
2) 변수 타입을 명시적으로 정해줄 수도 있다.
3) 이후에 수정이 될 수 없다. const와 유사한 역할.
4) 초기 데이터 없이 변수를 선언 할 수 있게 해준다.
5) js의 const와 다르다! dart의 const는 compile-time constant를 만든다. 컴파일 전에 값을 무조건 알면 사용하는 타입.

관습적으로 함수나 메소드 내부지역 변수를 선언할 때에는 var를 사용한다. Class에서 변수나 Property를 선언할 때에는 타입을 지정한다.

Dynamic 타입

var name; 또는 dynamic name;
name = 'String';
name = 1;
name = true;

위와 같이 변수가 타입이 지정되지 않은 Dynamic한 경우에는 어떠한 값이라도 들어갈 수 있게 된다. 위 타입은 추천되는 방식은 아니지만 때때로 유용하게 사용된다.

Null Safety

void main() { 
  String? name = 'John'; // null이 들어 갈 수 있는 변수 name
  name?.isNotEmpty; //name이 null이 아니라면 not Empty
}

위처럼 변수에 ?를 추가 하여 해당 변수에 null이 들어갈 수 있음을 명시 해준다. 만약 ?가 없는 경우에는 해당 변수에 null 값이 들어갈 수 없다. 이를 통해 null 값 참조를 통한 런타임 에러가 발생하는 것을 방지한다.

2. 자료형

Dart에서는 모든 자료형, 함수들은 object로 이루어져있다.
Class로 이루어져있기 때문에 import 없이 다양한 메서드를 사용할 수 있다.

기본 자료형 : String, boolean, int, double, num (int or double)

복잡한 자료형 : Lists, String Interpolation, Collection, Maps, Sets

  • List

  var numbers = [1, 2, 3, 4]; 
  List<int> numbers = [1, 2, 3, 4]; // 1,2 둘 다 동일하다
  • Collection if

void main() { 
  var giveMeFive = true;
  var numbers = [1, 2, 3, 4, if(giveMeFive) 5];
  print(numbers);
}

>> [1,2,3,4,5]

만약 collection if에 해당하는게 true라면 해당 값을 추가한다.

  • String Interpolation

    text에 변수를 추가하는 방법, $ 뒤에 변수명을 추가하여 변수 값을 넣을 수 있다.
  var name = 'John';
  var age = 20;
  var greeting = 'Hi, My name is $name and I\'m ${age + 1}';
  print(greeting);
  
  >> Hi, My name is John and I'm 21
  • Collection for

void main() { 
  var oldFriends = ['nic0', 'lynn'];
  var newFriends = [
    'lewis', 
    'ralph', 
    'darren',
    for (var friend in oldFriends) "OG $friend" ];

  print(newFriends);
}

>> [lewis, ralph, darren, OG nic0, OG lynn]

다른 배열에 있는 값을 배열 안에 넣어준다.

  • Map

  var players1 = {
    'name' : 'John',
    'xp' : 20.99,
    'superPower' : false,
  };
  Map<int, bool> players2 = {
    1: true,
    2: false,
    3: true
  };
  print(players2);

다른 언어에서의 Map과 동일한 역할, 키/값으로 값을 저장

  • Sets

  var players = {1,2,3,4,5};
  Set<int> numbers = {1,2,3,4,5};
  numbers.add(1);
  print(numbers);
  
  >> {1, 2, 3, 4, 5}

list와는 다르게 sets는 순서가 있으며, 모든 요소는 유니크하다. (Python의 tuple)

3. 함수

1. 선언

String sayHello(String name){
  return "Hello $name nice to meet you !";
}

void main() { 
  print(sayHello('Kim'));
}

>> Hello Kim nice to meet you !

num plus(num a, num b) => a + b; // A
void main() { 
  print(plus(4,5));
}

>> 9

A줄의 코드처럼 코드가 1줄인 경우 fat Arrow Syntax를 통해 간결하게 작성할 수 있다.

2. Named Parameter
여러 매개변수를 넘겨줄 때, 순서에 관계 없이 argument의 이름을 입력하여 전달. 기존 position parameter 처럼 순서를 외울 필요가 없다.

String hello({String name = 'anon', int age = 20, String country = 'Korea'}){
  return "Hi, I'm $name, and I am $age years old. I'm from $country.";
}

void main() { 
  print(hello(
    name: "John",
    age: 8,
    country : "korea",
  ));
}

>> Hi, I'm John, and I am 8 years old. I'm from korea.

위 방법은 사용자가 값을 입력하지 않는 상황을 대비하여 named parameter에 defalut 값을 지정해주거나, required Modifier를 사용하여야한다.

String hello({required String name, required int age, required String country}){
  return "Hi, I'm $name, and I am $age years old. I'm from $country.";
}

void main() { 
  print(hello(
    name: "John",
    age: 8,
    country : "korea",
  ));
}

required 라는 수식어를 매개변수 앞에 추가하여 해당 매개 변수가 필수임을 알리고, 이후에 만약 해당 함수를 사용할 때 required 매개변수가 입력되지 않으면 해당 코드는 Dart가 컴파일 하지 않는다.

3. Optional Positional Parameter

String hello(
    String name, int age, [String? country = 'Korea']) {
  return "Hi, I'm $name, and I am $age years old. I'm from $country.";
}

void main() {
  print(hello("John",8));
}

>> Hi, I'm John, and I am 8 years old. I'm from Korea.

위처럼 만약 Country라는 값만 기본 값을 설정해두고 nullable 하게 정하고 싶으면 대괄호를 사용하여 지정할 수 있다.

4. QQ Operator

String capitalizeName(String? name) => name != null ? name.toUpperCase() : 'ANON';

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

void main() {
  print(capitalizeName('John'));
  print(capitalizeName(null));
}

>> JOHN
   ANON

첫 번째 삼항 연산자를 사용한 코드와 두 번째 QQ 연산자를 사용한 코드는 동일하다.
만약 left ?? right 일때, left의 값이 null 이면 right를 return하고, 아니면 left를 return 한다.

  • QQ equals / QQ assignment operator
  void main() {
    String? name;
    name ??= 'John';
    name ??= 'Ben';

   print(name);
  }
  >> John

위 QQ equals는 만약 해당 변수의 값이 null인 경우에만 assign 하도록 한다.

5. typedef

typedef ListOfInt = List<int>;

ListOfInt reversedList(ListOfInt list) => (list.reversed).toList();

void main(){
  print(reversedList([1,2,3,4,5]));
}
>> [5, 4, 3, 2, 1]

위처럼 자주 사용되는 자료형은 alias (별칭)을 지정하여 작성할 수 있다.

4. 클래스

- class

class Player{
  final String name;
  int xp;
  
  Player(this.name,this.xp);
  
  void sayHello(){
    print(name + " and " + xp.toString());
  }
  
}

void main(){
  var player = Player("Kim", 25); 
  player.sayHello();
}

클래스의 프로퍼티들은 명시적으로 type을 지정해주어야 한다.
위 코드 처럼 생성자를 간결하게 작성할 수 있다.

class Player{
  final String name;
  int xp;
  String team;
  int age;
  
  Player({
    required this.name,
    required this.xp, 
    required this.team, 
    required this.age}
  );
  
  void sayHello(){
    print(name + " and " + xp.toString() + " and " + team + " and " + age.toString());
  }
  
}

void main(){
  var player = Player(
    name :"Kim", 
    xp : 25, 
    team: "team blue", 
    age: 20,
  ); 
  
  player.sayHello();
}

함수와 동일하게 named parameter를 적용할 수 있다.

  Player({
    required this.name,
    required this.xp, 
    required this.team, 
    required this.age}
  );
  
  Player.createBluePlayer({required String name, required int age}) :
  this.age = age, 
  this.name = name,
  this.team = 'Blue',
  this.xp = 0;

위처럼 특정 값만 입력하고 default값을 주고 싶으면 Name constructor를 사용하면 가능하다.

- Cascade Operator

class Player {
  String name;
  int xp;
  String team;

  Player(
      {required this.name,
      required this.xp,
      required this.team,
      });

  void sayHello() {
    print(name +
        " and " +
        xp.toString() +
        " and " +
        team);
  }
}

void main() {
 
  var John = Player(name : 'John', xp : 1200, team : 'Red')
  ..name = 'Ben'
  ..xp = 1200000
  ..team = 'blue'
  ..sayHello();
  
}

- Enum

enum Team {red, blue}

class Player {
  String name;
  int xp;
  Team team;

  Player(
      {required this.name,
      required this.xp,
      required this.team,
      });
}

실수 방지를 위해 Enum 타입으로 선언할 수 있다.

- 추상 클래스
다른 클래스들이 직접 구현해야하는 메소드들을 모아둔 일종의 BluePrint (청사진)이다.

enum Team {red, blue}

abstract class Human{
  void walk(){
    print('I walk slow');
  }
}

class Runner extends Human{
  String? name;
  int? xp;
  Team? team;
  
  Runner(
      {required this.name,
      required this.xp,
      required this.team,
      });
  
  void walk(){
    print('I walk fast.');
  }
}

void main(){
  var man = Runner(name : 'Ben', xp : 120, team : Team.blue)
    ..name = 'John'
    ..xp = 1200
    ..team = Team.red
    ..walk();
  
}

- 상속

enum Team {red, blue}

abstract class Human{
  final String name;
 
  Human({required this.name});
  
  void walk(){
    print('I walk');
  }
}

class Runner extends Human{
  
  final Team team;
  
  Runner({
    required this.team,
    required String name
  }) : super(name: name);
  
  @override
  void walk(){
    super.walk();
    print('faster than others.');
  }
}

void main(){
  var man = Runner(team : Team.blue, name : 'John');
  man.walk();
}

위처럼 추상클래스를 만들어 상속시킬 수 있다. 이때 부모 클래스의 변수나 메소드를 수정 및 상속 할 경우에는 super라는 키워드를 사용하여야한다.

부모 클래스의 생성자를 호출할 경우에는 super(name : name) 처럼 부모 클래스의 생성자에게 전달을 해주어야한다.

- Mixin -

  • 생성자가 없는 클래스.
    클래스에 프로퍼티를 추가할 때 사용.
class Strong{
  final double strength = 5000.0;
}

class StrongMan with Strong{
}

위 처럼 생성자가 없는 클래스를 Mixin 클래스로 With 키워드를 통해 해당 클래스의 프로퍼티를 가져올 수 있다. -> 클래스의 재사용성이 증가.

0개의 댓글