Dart – 기본기 (1)

Dart 변수 선언 / 할당

var

void main(){
  /* var 
   * js의 var와 비슷, 어떤 타입의 컨텐츠도 할당할 수 있음
   * 선언과 동시에 값을 할당하는 경우, dart는 해당 변수의 타입을 고정함.
   * 선언과 동시에 할당하지 않은 경우, 어떠한 데이터 타입도 저장할 수 있는 Dynamic Type 변수
   * */
  var name = 'dylan'; 
  var num = 1;  
  var dynamic;  //Dynamic Type 변수
  print(name.runtimeType); //String 타입
  print(num.runtimeType); // int 타입
}

integer / double

void main(){
  int num1 = 2; // int  
  double num2 = 0.5; // double 
}

boolean

void main(){
  bool isTrue = true; // boolean
}

String

void main(){
  String name = 'dylan';
  String job = 'engineer';
  
  print(name + job); dylanengineer
  print('$name is $job'); dylan is engineer
  print('${name} is ${job}'); dylan is engineer
}

Dynamic

void main(){
  /*
   * var vs dynamic
   * runtimeType을 보면 var 와 동일하게 String
   * dynamic 으로 값이 할당되면, 재할당시 타입과 상관없이 변경 가능
   * */
  dynamic name = 'dylan';
  var name1 = 'dylan';
  
  name = 1; // dynamic 으로 선언/할당되면 다른 타입으로 변경 가능
  name1 = 1; // var로 선언/할당되면 타입이 고정되어 다른 타입으로 변경 불가(에러 발생)
  
  print(name.runtimeType);
  print(name1.runtimeType);
}

nullable, non-nullable, null

void main(){
  /*
   * nullable - null이 될 수 있다.
   * non-nullable - null이 될 수 없다.
   * */
  String name = 'Dylan';
  name = null; //error
  
  String? name2 = 'Dylan'; // 물음표를 붙이면 null 까지 들어갈 수 있는 데이터 타입을 의미한다.
  print(name2!); // 느낌표를 붙이면 현재 이 변수는 null 이 아니라는 것을 의미한다.
}

final, const

void main(){
  final String name = 'Dylan'; // final 을 쓰면, 변수의 값을 변경할 수 없다.
  name = 'change the name'; // error
  
  const String name2 = 'Dev'; // const 도 변수의 값을 변경 할 수 없다.
  name2 = 'change the name2'; //error
  
  final team = 'DevOps'; // const나 final 을 쓰면 타입 생략 가능(var 역할을 해줌)
  
  
  
  /* final vs const */
  final DateTime now = DateTime.now();  // error :: build 되는 시점에 값을 몰라도 됨
  const DateTime now2 = DateTime.now(); // error :: build 되는 시점에 값을 알고 있어야함 (DateTime은 코드가 실행되는 시점의 시간을 가져오기때문에)
}

List

void main() {
  /*
   * generic 기호를 사용하여 내부 데이터의 데이터 타입 정의
   * */
  List<String> numList = ['일', '이', '삼', '사', '오'];
  List<int> numList2 = [1, 2, 3, 4, 5];
  List<dynamic> mixedList = ['일', 2, '삼', 4, '오']; // 여러 데이터 타입 데이터를 포함하고 싶은 경우
  var mixedList2 = ['일', 2, '삼', 4, '오'];

  print(mixedList);
  print(mixedList2);

  numList.add('육'); // data append
  numList2.remove(5); // data remove
  numList.indexOf('일'); // 0

}

Map

void main() {
  /*
   * 일반적인 Object를 dart에서는 Map 으로 표현
   * */
  Map<String, String> dictionary = {
    // generic에 key value 의 데이터 타입을 각각 기입. 혹시 타입을 특정할 수 없다면 dynamic
    'Harry Potter': '해리포터',
    'Ron Weasley': '론 위즐리',
    'Hermione Granger': '헤르미온느 그레인저'
  };
  Map<String, dynamic> test = {'integer': 1, 'String': '일'};

  Map<String, bool> isHarryPotter = {
    'Harry Potter': true,
    'Ron Weasley': true,
    'Ironman': false,
  };

  isHarryPotter.addAll({
    // Map에 데이터 append
    'Spiderman': false,
  });

  print(isHarryPotter['Ironman']); // key로 value 추출 가능
  isHarryPotter['Hulk'] = false; // 임의적으로 추가 가능
  isHarryPotter['Spiderman'] = true; // 값 변경 가능
  isHarryPotter.remove('Harry Potter'); // 값 삭제 가능
  
  print(isHarryPotter.keys); // key값들 추출가능
  print(isHarryPotter.values); // key값들 추출가능
}

Set

void main() {
 /*
  * List와 아주 유사하나 List은 중복값이 들어갈 수 있고, Set은 중복값이 들어갈 수 없다
  * 중복을 자동으로 처리해줌.
  * */ 
  
 final Set<String> names = {
   'dylan',
   'Flutter',
   'Engineer',
   'dylan',
 };
  
  print(names); //{dylan, Flutter, Engineer}
  
  names.add('test'); // 값 추가
  names.remove('test'); // 값 제거
  
  print(names.contains('dylan')); //true
}

enum

/*
 * enum을 쓰는것은 정의된 타입만 사용할 수 있게 강제하기 위함이다.
 * string으로 비교하면 오타가 날 수 있고, 가독성이 떨어짐
 * */

enum Status {
  approved,
  pending,
  rejected,
}

void main() {
 Status status = Status.pending;
  
  if(status == Status.approved) { 
    print('승인');
  }else if( status == Status.pending){
    print('대기');
  }else {
    print('거절');
  }
}

typedef

void main() {
  int result = calculate(10, 20, 30, add);
  print(result);
}

typedef Operation = 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, Operation operation) => operation(x, y, z);

함수 / 파라미터 종류 / return type

void main() {
  int sum = addNumbers(1, 2, 3);
  int sum1 = addNumbersOption(1);
  int sum2 = addNumbersNamed(y: 10, x: 20, z: 30);
  int sum3 = addNumbersNamedOption(x: 10, y: 20);
  int sum4 = addNumbersNamedPostional(10, y: 20, z: 30);
}

// positional parameter - 순서가 중요한 파라미터
int addNumbers(int x, int y, int z) {
  int sum = x + y + z;
  return sum;
}

// optional parameter - 파라미터가 필수가 아닐땐 []괄호사용
// null 값이 들어갈 수 있도록 데이터 타입에 ? 붙여줘도됨.
// 파라미터를 받을때 필수가 아니라면, 기본값을 넣어주자
int addNumbersOption(int x, [int y = 0, int z = 0]) {
  int sum = x + y + z;
  return sum;
}

// named parameter - 이름이 있는 파라미터 (순서가 중요하지 않음)
// 모든 파라미터가 필수일 경우
int addNumbersNamed({
  required int x,
  required int y,
  required int z,
}) {
  int sum = x + y + z;
  return sum;
}

// named parameter - 이름이 있는 파라미터 (순서가 중요하지 않음)
// 파라미터가 필수가 아닐 경우
int addNumbersNamedOption({
  required int x,
  required int y,
  int z = 30,
}) {
  int sum = x + y + z;
  return sum;
}

// named parameter와 positional parameter 을 같이 사용
int addNumbersNamedPostional(
  int x, {
  required int y,
  required int z,
}) {
  int sum = x + y + z;
  return sum;
}

// 모든 데이터 타입을 리턴할 수 있다.
Map returnMa() {
  Map<String, String> mapSample = {'name': 'dylan'};
  return mapSample;
}

arrow function

void main() {
  int sum = addNumber(10, y: 20, z: 30);
}

// arrow function
// syntax : returnType functionName(parameters...) => expression;
int addNumber(
  int x, {
  required int y,
  required int z,
}) =>
    x + y + z;

비교 연산

void main(){
  int number1 = 1;
  
  print(number1 is int); //true
  print(number1 is String); //false
  print(number1 is! int); // false
  print(number1 is! String); // true
  
}

Loop

void main() {
  int total = 0;
  List<int> numbers = [1, 2, 3, 4, 5, 6];

  for (int i = 0; i < numbers.length; i++) {
    total += numbers[i];
  }

  total = 0;
  for (int number in numbers) {
    total += number;
  }

  total = 0;
  while (total < 10) {
    total += 1;
  }
}

null 값 초기화 시 유용한 팁

void main(){
  /* ??= */
  double? number = 4.0;
  number = null;
  number ??= 3.0; // number 가 null이면 오른쪽 값으로 변경
  print(number); // 3
}