My Space

Dart 언어

2024. 4. 20. 23:58
반응형

Dart 란?

- 객체지향 언어로, User Interface를 만드는데에 최적화가 되어있다.

- null safety 사용

- JIT, AOT 두가지의 컴파일러 사용

 : 개발속도를 높히기 위해 dart팀에서 JIT컴파일러를 개발

- Flutter, dart 모두 구글에서 만들었기 때문에 flutter의 속도를 향상시키기 위해 dart언어 자체를 수정하기도 한다.

 : Flutter에서 성능이 떨어지는 부분이 있으면 dart 언어자체를 개선해서 향상 시키기도함. 이는 엄청난 장점이된다

 ex) 리액트팀이 성능을 개선하기 위해 javascript를 수정할 수가 없지만, Flutter/dart는 구글에서 개발했기 때문에 가능

Dart Native (JIT and AOT 컴파일러)

Dart 컴파일러 종류

JIT(just-in-time)

- dart VM 사용

- 개발중에서만 사용됨(for dev)

- 작성한 코드를 화면에서 빠르게 볼 수 있음

AOT(ahead-of-time)

- 컴파일을 먼저하고, 그 결과인 바이너리를 배포(익숙한 방식)하기 때문에 시간이 많이 걸린다.(개발 도중 컴파일러를 하기때문에 UI변경에도 시간 소요)

정리

- 개발시에는 JIT 컴파일러를 사용해 속도를 높히고, 배포시에는 AOT 컴파일러를 사용하기 때문에 dart가 특별하고 좋은 언어(개발자 친화적)

VARIABLES

main 함수는 모든 Dart 프로그램의 Entry point.

dart는 자동으로 main 함수를 찾아서 실행하기 때문에, main 이름을 변경하면 실행이 불가능

 

1. var(타입 추론)

     - 함수나 메서드 내부에 지역변수를 선언할때 주로 사용한다.(타입을 명시해도 동일)

     - class에서 변수를 선언하거나 property를 선언할 때는 타입을 명시

     - 변수의 값 수정은 동일한 타입으로만 가능하다.

       ex) var name = '테스터';    name = 1;  <- 이런식으로 문자열로 선언한 값을 다른 타입의 값으로는 불가

 

2. dynamic

     - 여러가지의 타입을 가질 수 있다

     - var 키워드로는 선언한 타입을 그대로 따라가지만, dynamic는 변경 가능

void main() {
	dynamic name;
	// name. <-- 소수의 메서드만 자동완성으로 나온다(타입이 명확하지 않기 때문)
	if(name is String) {
		name.length // String 타입으로 넘어왔기 때문에 String 메서드 모두 사용가능
	}
	if(name is int) {
		name.isOdd // int 타입으로 넘어왔기 때문에 int 메서드 모두 사용가능
	}
}

 

3. final

     - 선언 후 수정할 수 없는 변수

        ex) final name = 'tester'; 또는 final String name = 'tester';로 선언

     - 컴파일러가 타입추론을 잘해주기 때문에 굳이 final 뒤에 타입을 명시할 필요는 없다

     - javscript에서의 const와 비슷

 

4. const

      - javascript의 const와 다르다

      - compile-time constant로 컴파일 할 때, 알고 있는 값에 사용(앱스토어에 앱 올리기 전에 알고 있는 값)

         ex) max_allowed_price

      - API 통신으로 받아온 값들은 const로 사용할 수 없다(컴파일 후에 넘어온 값들이기 때문)

      - (장점)메모리 효율성을 높이기 위함

      - (장점)런타임 오버헤드를 줄이기 위함

void main() {
	const name = 'tester';  // 컴파일 시점에 변경X
	final username = fetchAPI();  // 컴파일 이후에 변경O
}

 

5. Null Safety

      - 개발자가 직접 null을 참조할 수 없다

      - nullable를 선언하고 싶으면 ? 키워드 사용     

void main() {
	String? name = 'tester';
	name = null;  <- 위에서 ?로 선언을 안하면 이부분 에러 발생
	if (name != null) {
		name.isNotEmpty;
	}
}

/* 아래 두 코드는 같은 결과를 반환 */
if (name != null) {
		name.isNotEmpty;
}
// 단축 문법
name?.isNotEmpty;  // name이 null이 아니면 isNotEmpty반환

 

6. late

      - final 또는 var 앞에 붙여주는 수식어(flutter에서 API 호출할때 많이 사용)

      - 초기 데이터 없이 변수 선언

         ex) late final String name;

      - late 수식어로 선언한 변수에 값이 없으면 print() 등으로 뽑을 수 없다(컴파일 에러)

 

요약

1. var 변수명 = 변수값

     - 처음 할당한 변수값과 같은 타입으로만 업데이트 가능

2. String 변수명 = 변수값

     - 명시적으로 설정한 타입(String)으로만 업데이트 가능

3. String? 변수명 = 변수값

     - 명시적으로 설정한 타입(String) 외에 Null 타입으로도 업데이트 가능

4. dynamic 변수명 = 변수값

     - 처음 할당한 변수값과 다른 타입으로도 업데이트 가능

5. final 변수명 = 변수값

     - 한번 할당한 변수값을 바꿀 수 없음

6. late final String 변수명

     - 처음 변수명을 선언할 때 변수값을 할당하지 않아도 되며, 나중에 명시적으로 설정한 타입(String)으로 변수값을 설정할 수 있음. 한번 할당한 변수값을 바꿀 수 없음

7. const 변수명 = 변수값

     - 컴파일하기 전(앱을 실행하기 전)에 미리 변수값을 정해줘야 함(compile-time constant). 한번 할당한 변수값을 바꿀수 없음

 

Date Types

String, bool, int, double, num을 포함한 거의 대부분의 타입들이 객체로 이루어져 있다(함수 포함)

이러한 이유로 Dart가 진정한 객체 지향 언어이다.

 

List 객체 선언

void main() {
	var numbers = [1, 2, 3, 4];
	// List<int> numbers = [1, 2, 3, 4];	
}

 

dart에서는 collection ifcollection for을 지원한다

/** collection if 예제 **/
void main() {
	var giveMeFive = true;
	var numbers = [1, 2, 3, 4, if(giveMeFive) 5,];		
	
	// collection if를 사용하지 않으면 아래와 같음
	if (giveMeFive) {
		numbers.add(5);
	}
}

/** collection for 예제 **/
void main() {
  var oldMembers = ['testerA', 'testerB'];
  var newMembers = [
    'testerC',
    'testerD',
    'testerE',
    for (var member in oldMembers) member,
  ];
  print(newMembers);
}

 

문자열에 변수 사용 및 계산($)

void main() {
  var name = 'tester';
  var age = 20;
  var greeting = "Hello everyone, my name is $name and I'm ${age + 2} nice to meet you!";
  print(greeting);
}

 

Map

void main() {
  var player = {
    'name': 'tester',
    'xp': '19.99',
    'superpower': false,
  };
  print(player);
}

 

Set(유니크한 값 저장)

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

 

Function

Named parameters

함수의 매개변수 위치에 맞게 파라미터를 넣어주는게 아니라 네이밍으로 매칭

/** 기본 함수 매개변수 사용 **/
String sayHello(String name, int age, String country) {
  return "Hello $name, you are $age, and you come from $country";
}
void main() {
  print(sayHello('tester', 20, 'kr'));
}

/** named parameter사용(디폴트값 추가) **/
String sayHello({
	String name = 'tester',
	int age = 99, 
	String country = 'us'
	}) {
  return "Hello $name, you are $age, and you come from $country";
}
void main() {
  print(sayHello(
      age: 20,
  ));
}

/** named parameter사용(필수 입력값) **/
String sayHello({
	required String name,
	required int age,
	required String country
	}) {
  return "Hello $name, you are $age, and you come from $country";
}
void main() {
  print(sayHello(
      age: 20,
      country: 'kr',
      name:'tester',
  ));
}

/** Optional Positional Parameter **/
/** 잘 사용하지는 않는다. country가 널일수 있고 널인경우 디폴트 값 지정 **/
String sayHello(String name, int age, [String? country = 'kr']) {
  return "Hello $name, you are $age, and you come from $country";
 } 
void main() {
  print(sayHello('tester', 20));
}

dart는 null safety가 적용되기 때문에 named parameter을 사용할 경우, 매개변수에 default값을 지정해주거나 required로 필수값 지정을 해줘야 한다.

 

QQ(Question Question) Operator (?? 연산자)

정의: left ?? right; 가 있을 경우, 좌항이 null이면 우항을 return

/** 이름을 받아 대문자로 출력. 파라미터가 null일 수 있다. **/

// case1. if로 분기태우는 방식
String capitalizeName(String? name) {
  if (name != null) {
    return name.toUpperCase();
  }
  return 'ANON';
}

// case2. 삼항 연산자
String capitalizeName(String? name) {
	return name != null? name.toUpperCase() : 'ANON';
}

// case3. ?? 연산자
String capitalizeName(String? name) {
	return name?.toUpperCase() ?? 'ANON';  //name가 널일수 있어서 ? 추가
}

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

추가로, ??= 연산자를 이용해서 변수 값이 null일때 체크해서 값 할당 가능

ex) String? name;

      name ??= 'tester';

 

Typedef

자료형에 사용자가 원하는 alias를 붙일 수 있음

ex) typedef UserInfo = Map<String, String>; 를 선언하면, 

      String sayHi(Map<String, String> userInfo) {} 대신

      String sayHi(UserInfo userInfo) {} 로 사용 가능.

 

CLASS

class Player {
  // property를 선언할 때는 타입을 정의
  final String name = 'tester';
  int xp = 1500;

  void sayHello() {
    print("Hi my name is $name and my xp is $xp");
  }
}

void main() {
  // 함수내에서는 타입을 굳이 정의 할 필요없이 var 사용
  var player = Player(); // new Player()로 new 키워드를 써도 가능
  player.sayHello();
}

 

1. position parameter

class Player {
  // late final String name;
  // late int xp;
  //
  // Player(String name, int xp) {
  //   this.name = name;
  //   this.xp = xp;
  // }
  
  // 위의 주석부분들을 아래와 같이 단축사용할 수 있다
  final String name;
  int xp;

  Player(this.name, this.xp);

  void sayHello() {
    print("Hi my name is $name, xp is $xp");
  }
}

void main() {
  Player player1 = Player('tester1', 1500);
  player1.sayHello();
  Player player2 = Player('tester2', 3500);
  player2.sayHello();
}

 

2. named parameter

/** 파라미터가 여러개일 경우 named parameter 사용 **/
class Player {
  final String name;
  int xp;
  String team;
  int age;

	// Named Constructors Parameters
  Player({
    required this.name,
    required this.xp,
    required this.team,
    required this.age,
  });

  void sayHello() {
    print("Hi my name is $name, xp is $xp");
  }
}

void main() {
  Player player1 = Player(
      name: 'tester1',
      xp: 1500,
      team: 'red',
      age: 12,
  );
  player1.sayHello();
  Player player2 = Player(
    name: 'tester2',
    xp: 5500,
    team: 'blue',
    age: 22,
  );
  player2.sayHello();
}

 

3. named constructors

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

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

 // dart문법 (:) 키워드로 객체 초기화(플러터에서 많이 사용)
  Player.createBluePlater({
    required String name,
    required int age,
  }) : this.age = age,
       this.name = name,
       this.team = 'blue',
       this.xp = 0;

  void sayHello() {
    print("Hi my name is $name, xp is $xp");
  }
}

void main() {
  Player player1 = Player.createBluePlater(
      name: 'tester1',
      age: 12,
  );
}

 

4. Json 데이터 받아오는 형식 예제

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

  Player.fromJson(Map<String, dynamic> playerJson)
      : name = playerJson['name'],
        xp = playerJson['xp'],
        team = playerJson['team'];

  void sayHello() {
    print("Hi my name is $name, xp is $xp, team is $team");
  }
}

void main() {
  var apiData = [
    {
      "name": "tester1",
      "team": "red",
      "xp": 15000,
    },
    {
      "name": "tester2",
      "team": "blue",
      "xp": 25000,
    },
    {
      "name": "tester3",
      "team": "green",
      "xp": 35000,
    },
  ];
  
  /*
  apiData.forEach((playerJson) {
    var player = Player.fromJson(playerJson);
    player.sayHello();
  });
  */
  // 위 foreach와 동일
  for (var playerJson in apiData) {
    var player = Player.fromJson(playerJson);
    player.sayHello();
  }
}

 

5. Cascade Notation

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

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

  void sayHello() {
    print("Hi my name is $name, xp is $xp, team is $team");
  }
}

void main() {
  // var player = Player(name: 'tester1', xp: 35000, team: 'red');
  // player.name = 'noname';
  // player.xp = 1000;
  // player.team = 'black';

	// dart에서 아래와 같이 객체를 선언하면서 .. 키워드로 값 변경 및 함수 호출 가능
  var player = Player(name: 'tester1', xp: 35000, team: 'red')
  ..name = 'noname'
  ..xp = 1000
  ..team = 'black'
  ..sayHello();
}

 

6. Enum

enum Team {red, blue}
enum XPLevel {beginner, medium, pro}

void main() {
  var player = Player(name: 'tester1', xp: XPLevel.beginner, team: Team.blue)
  ..name = 'noname'
  ..xp = XPLevel.medium
  ..team = Team.red
  ..sayHello();
}

 

7. Abstract Class

추상화 클래스로는 객체생성X

abstract class Human {
  void walk();
}

class Player extends Human {
  void walk() {
    print('im walking');
  }
}

class Coach extends Human {
  void walk() {
    print('the coach is walking');
  }
}

void main() {
  var player = Player().walk();
  var coach = Coach().walk();
}

 

8. Inheritance(상속)

super : 상속한 부모 클래스의 프로퍼티에 접근 및 메서드 호출가능

class Human {
  final String name;
  Human({required this.name});
  void sayHello() {
    print("Hi my name is $name");
  }
}

class Player extends Human {
  final String team;

  Player({required this.team, required String name}) : super(name: name);

  @override
  void sayHello() {
    super.sayHello();
    print("and i play for $team");
  }
}

void main() {
  var player = Player(team: 'blue', name: 'tester1')..sayHello();
}

 

9. Mixin

생성자가 없는 클래스

상속과는 다르게 단순히 mixin 내부의 프로퍼티와 메소드를 가져오는 것 뿐.(부모 자식 관계X)

mixin Strong {
  final double strengthLevel = 1500.99;
}

mixin QuickRunner {
  void runQuick() {
    print("ruuuuuuuuuun!");
  }
}

mixin Tall {
  final double height = 1.99;
}

class Player with Strong, QuickRunner, Tall {
  final String team;

  Player({required this.team});
}

'Development > APP' 카테고리의 다른 글

FLUTTER 실습  (0) 2021.12.20
FLUTTER 시작  (0) 2021.12.18

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading