Dart

염지현·2023년 12월 26일

flutter

목록 보기
1/2

Dart

  • flutter 맞춤형 객체지향언어
  • 구글에서 만듦
    - flutter와 dart 모두 구굴이 만들었기 때문에 지속적인 최적화가 진행될 것
    • react는 facebook 것인데 내가 react를 빨리 하고 싶다고 해서 javascript 언어 체계를 수정하지 못하는 데에 비해 dart는 보다 수월함
  • user interface를 위한 언어
  • 생상적인 개발환경
  • 모든 프랫폼에서 빠름
    1. 2개의 컴파일러를 가지고 있음
    - dart web: 작성한 코드를 javascript로 변환해주는 컴파일러
    - dart native: dart 코드를 여러 CPU 아키텍처에 맞게 변환 -> 예를 들어 arm32, arm64, 데스크탑 cpu에 맞추어 변환 -> 따라서 ios, android, windows, linux, mac으로 컴파일이 가능하다는 것
    1. 컴파일 방법: JIT(just-in-time) & AOT(ahead-of-time)
      • AOT(ahead-of-time): 컴파일은 먼저 한 후에 그 결과인 바이너리(기계어)를 배포 배포시
        - c, c++ 등의 언어로 코딩을 한 후 컴파일 할 때 아키텍처를 지정해줘야 한다. 예를 들어 c++ 언어로 프로그램을 완성하고 windows로 배포하고 싶을 때 c++ 코드를 windows 바이너리로 컴파일하여 제공
        • 그러나 이런 컴파일 과정은 최적화와 바이너리 코드로 변환하기 때문에 시간이 오래 걸린다. 따라서 중간에 코드를 수정하고 처음부터 컴파일 하는 것은 매우매우 비효율적. 이를 해결하기 위해 등장한 것이 just-in-time 컴파일러이다.
      • JIT(just-in-time) 개발중
        - dart VM을 사용하는데 내 코드의 결과를 바로 화면에 보여준다.
        • 물론 VM에서 하는 거라 시간은 꽤 걸리지만 이건 오직 개발 중일 때만 사용한다.
          - 풍부한 디버깅 및 자원 --> 내가 쓴 코드의 결과를 몇 초만에 확인 가능
        • 하지만 이거는 VM이기 때문에 실제 배포할 때는 AOT 컴파일러를 사용
  • null safety: 안전한 프로그램을 빌드할 때 매우 중요
    - 개발자가 null 값을 참조해버리면 모든 것이 고장남. 이를 해결하기 위해 null safety로 방지함

Dart 실습

link: dartpad.dev 로 가면 바로 dart 언어를 사용할 수 있는 tool이 제공되는 웹사이트로 갈 수 있음

1. Variable

1.0 Hello, world

void main() {
  for (int i = 0; i < 5; i++) {
    print('hello ${i + 1}');
  }
}

// 메인 함수를 호출해서 run 하기 때문에 main 함수가 있어야 함
// 세미콜론을 꼭 달아줘야 함. 왜냐하면 필요에 따라 세미콜론을 안 쓸 수도 있기 때문

1.1 var & String과 같은 type 지정

void main() {
  var name = 'abc'; // type을 추출함
  // name 에는 이미 스트링 문자열을 넣어주었기 때문에 값을 업데이트 할 수는 있지만 문자열로만 업데이트가 가능함
  // 즉, 정수, bloo 등과 같은 다른 타입을 넣을 때는 업데이트가 불가능함
  // 관습적으로 함수나 메소드 내부에서 지역 변수를 선언할 대는 var를 사용
  // var를 사용하는 편
  
  String name2 = 'abc';
  // var 대신 명시적으로 타입을 정해줄 수 있음
  // class에서 변수나 property를 선언할 때 타입 지정   
}

1.2 Dynamic Type

Dynamic: 타입을 지정하지 않는 형식 -> 굉장히 유용하지만 그만큼 위험할 수 있기 때문에 꼭 필요할 때만 사용하는 것을 지향

void main() {
  // dynamic: 여러가지 타입을 가질 수 있는 변수에 쓰는 키워드
  // 그만큼 유용하지만 정말 필요할 때만 사용해야 함 !! 주의 !!
  var name; // var로 변수를 선언하고 값을 초기화해주지 않으면 이 때 타입은 dynamic
  dynamic name2; // dynamic으로 선언 가능
  
  if (name is String){
    // 이 내부 조건문에서는 named이 String 이어야만 들어올 수 있음
    // 따라서 name은 String이 됨
    // name.을 치고 호출 가능한 함수 리스트를 확인할 수 있음
  }
  
  
  
  name = 'jh';
  name = 12;
  name = true;
   
}

1.3 Nullable Variables

  1. null safety: 개발자가 null 값을 참조하지 못하도록 하는 것
  • 따라서 null 값을 참조할 경우 error가 뜸
  • dart에서는 어떤 변수가 null이 될 수 있음을 정확히 표시해야 함
void main() {
  // null safety
  // dart에서는 어떤 변수가 null이 될 수 있음을 정확히 표시해야 함
  String jh = 'jh';
  // jh = null; // 이거는 String 형 변수에 null로 업데이트하는 것이기 때문에 불가능
  
  // null 값을 허용하려면 타입 뒤에 ? 만 붙여주면 됨
  String? jh2 = 'jh';
  jh2 = null;  // jh2.length를 사용할 수 있으나 null 값이 들어갈 수도 있음
  
  if (jh2 != null){ // null 값이 아닐 경우 처리할 수 있는 조건문을 달 수 있게 됨(null safety)
    jh2.isNotEmpty; 
  }
  
  // 조건문을 사용할 경우 시간 효율이 떨어짐 따라서 ?를 사용하여 값의 존재 여부 체크 후 연산 진행
  jh2?.isNotEmpty; // jh2가 null이 아니라면 isNotEmpty 속성을 달라고 요청하는 것
  
   
}

1.4 Final Variables

  • Final은 var와 다르게 값을 수정할 수 없는 역할을 한다.
void main() {
  final name = 'jh';
  // final은 var과 다르게 변수의 값을 수정할 수 없음
  // javascript, typescript의 const와 같음
   
}

1.5 Late Variables

  • late: final이나 var 앞에 붙어서 초기값 없이 변수를 선언할 수 있도록 도와줌 -> 따라서 API 요청으로 값을 받아올 때 유용하게 사용 가능
void main() {
  late final String name;
  // late는 초기 데이터 없이 변수 선언을 가능하도록 도와줌
  // API 요청으로 데이터를 받은 후 name에 나중에 데이터를 넣어줌
  // final은 수정 금, var만 수정 가능
  // late는 값이 할당되기 전까지 값을 가져올 수 없도록 제한함 -> 실수 방지
}

1.6 Constant Variables

  • const: final처럼 값을 수정하면 안 될 때 사용하는데 차이점은 compile-time 때 값을 알고 있어야 한다.
  • final, var는 사용자가 앱을 실행할 때 입력하는 값을 받아올 수 있지만 const는 앱을 배포하기 전에 반드시 가지고 있어야 하는 값을 저장할 때 사용한다.
void main() {
  // compile-time constant
  const name = 'jh';
  // const는 값을 수정하지 못한다.
  // 가장 중요한 것은 const는 compile-time에 알고 있는 값이어야 한다.
    // const API = '121212'; -> API 키를 하드코딩한 것이기 때문에 컴파일 타임에 알고 있음
    // const API = featchApi(); -> API에서 받아와야 하기 때문에 컴파일러는 API 변수의 값을 모름 -> 이 경우에는 final이어야 함
  // 앱에서 사용되는 상수들에는 const 사용
  
}

1.7 Recap

void main() {
  // var: 여러 번 값을 수정할 수 있는 var, type 지정
  int i = 12;
  var name = 'jh';
  // 위 형식은 타입을 지키면서 무한하게 수정 가능
  // dart 스타일 가이드에서는 'var'를 사용하도록 권장 
  
  // final: 값을 수정하지 못하도록 하는 final 
  final k = 12;
  
  // dynamic: 형식을 지정해주지 않고 나중에 지정 -> 값이 나중에 들어온다(조심히 사용할 것)
  // dynamic과 조건문(if dynamic 변수에 값이 들어왔다면)은 함께 사용하는 습관
  dynamic j; 
  
  // const: 컴파일 할 때 알고있어야 하는 값 (ex. API key) -> 수정 불가
  const api_key = '121212';
  
  // null safety: 잘못된 상태의 변수 참조 방지 -> null 참조 불가
  String? isnull_ = 'ss';
  isnull_?.isEmpty;
  
  // late: 아직 어떤 데이터가 들어올지 모름 -> API로 값을 받아올 때 효과적
  late final String name_; 
  
  
}

2. DATA TYPES

2.0 Basic Data Types

  • 모든 type은 class(object 형태임)
  1. String
  2. bool
  3. int
  4. double
  5. num -> int와 double의 부모 class이므로 num을 선언하면 정수, 실수 두 가지를 모두 넣을 수 있음
void main() {
  String name = 'jh';
  bool alive = true;
  int age = 25;
  double money = 67.99;
  num x = 12;
}

2.1 Lists

  • 배열
  • 같은 타입 원소로만 구성해야 함
  • var numbers = []나 List = [] 로 선언 및 초기화 가능
  • collection if -> if 문을 통해 원소를 추가할 수 있음(아래 예제 코드)
void main() {
  var giveMeFive = true;
  var numbers = [1,
                 2,
                 3,
                 4,
                if (giveMeFive) 5]; // collection if 
  print(numbers);
  List<int> nums = [1,2,3,4,];
  // int 형 list에는 반드시 int 형 값만 들어가야 함
  numbers.add(1);
  numbers.last; // 마지막 원소 값이 궁금할 때
  
  
}

2.2 String Interpolation

  • Striing interpolation: text에 변수를 추가하는 방법
void main() {
  var jh = 'jh';
  var age = 10;
  var greeting = "Hello everyone, my name is $jh, and I'm ${age+2}";
  print(greeting);
  // 단순히 호출: $기호 뒤에는 반드시 변수를 넣어주면 됨 -> $jh
  // 연산을 원한다면 %{}에서 계산 진행 -> ${age+2}
}

2.3 Collection For

  • for 문을 통해 원소를 추가하는 방법
  • 아이콘을 쓸 수 있는게 너무 신기..
void main() {
  var oldFriends = ['nico','lynn'];
  var newFriends = [
    'lweis',
    'ralph',
    'darren',
    for(var friend in oldFriends) "💖 $friend"
  ];
  print(newFriends);
}

2.4 Maps

  • 파이썬의 딕셔너리
  • List<Map<String, Object>>와 같이 딕셔너리를 리스트로 저장하는 것은 지양. 이 대신 class를 추천.
void main() {
  var player = {
    'name':'jh',
    'xp': 19.99,
    'superpower':true
  }; // python의 딕셔너리
  Map<int, bool> players = {
    1: true,
    2: false,
    3:true
  };
  Map<List<int>, bool> players_ = {
    [1,2,3,4]:true,
  };
  List<Map<String, Object>> players2 = [
    {'name':'jskdf', 'xp':1212},
    {'name':'sdf', 'xp':123123},    
  ];
}

2.5 Sets

  • 중복 없는 리스트
  • python의 tuple과 비슷함
void main() {
  var numbers = {1,2,3,4};
  Set<int> nums = {1,2,3,4,};
  numbers.add(1);
  print(numbers);
}

3. FUNCTIONS

3.0 Defining a Function

  • 함수의 구성
String sayHello(String name){ // void: 아무것도 return 하지 않는다.
  return ("Hello $name nice to meet you");  
}

String oneline(String name) =>  '❤️ $name'; // 함수가 한 줄이면 return을 => 표현할 수 있음.

num plus(num a, num b) => a+b;

void main() {
  print(sayHello('jh'));
  print(oneline('jh'));
}

3.1 Named Parameters

  • name parameters
    - 파라미터의 순서를 고려하지 않아도 됨
    • 내가 이해한 바는 파라미터를 딕셔너리 형태로 주기 때문에 순서에 상관없이 변수명: 변수값으로 줄 수 있음
      • 자동완성 기능도 사용할 수 있음
  • 방법1: default value를 설정하면 함수명만 호출해도 문제X
  • 방법2: 사용자에게 반드시 값을 받아야 할 경우 required [변수타입][변수명] 으로 작성하면 값을 받기 전까지는 함수가 컴파일 되지 않음
String sayHello({required String name, 
                 required int age, 
                 required String country}){
  return 'Hello, $name you are $age, and you com from $country';
}
// parameter 부분을 중괄호로 묶어주는 것이 named parameters
// null safety가 적용되기 때문에 미리 파라미터 값을 설정해줌

void main(){
  print(sayHello(
    name: 'jh',
    age: 24,
    country:'KR',
  ));
  // named argument: 파라미터의 순서 상관없이 호출할 수 있는 방법
  
  // print(sayHello()); 
  // null safety 때문에 미리 값을 초기화해주었기 때문에 값이 들어가지 않아도 괜찮음(defaut value가 정해졌다면)
  // 파라미터 앞에 required가 붙으면 필수적인 값이기 때문에 빈 값으로 넣을 수 없음
}

3.2 Recap

// positional parameters
String sayHello(String name, String country, int age){ 
  return 'Hello $name, you are $age, and you come from $country';
} 

// named parameters + default value
String sayHello2({String name='aa', String country='kr', int age=99}){ 
  return 'Hello $name, you are $age, and you come from $country';
} 

// named parameters + required
String sayHello3({required String name, 
                  required String country, 
                  required int age}){ 
  return 'Hello $name, you are $age, and you come from $country';
} 

void main(){
  // positional parameters 호출
  sayHello('jh', 'kr', 99);
  
  // named parameters 호출 + default value 설정
  sayHello2(
  name: 'jh',
  age: 99,
  country: 'kr');
  
  // named parameters 호출 + required
  sayHello3(
  name: 'jh',
  age: 99,
  country: 'kr');
} 

3.3 Optional Positional Parameters

  • 특정 원소를 optional(주거나 주지 않거나)하게 받거나 처리
String sayHello(String name, 
                int age, 
                [String? country='kr']) => // country는 null이 될 수 있다. 
  "Hellow $name, you are $age, you com from $country";

void main(){
  var results = sayHello('jh',99);
  print(results);
}

3.4 QQ operator(question question, null aware operator)

  • ??
String capitalizeName(String? name){ // name의 문자를 대문자로 수정하는 함수, null이 들어올 경우를 조건문으로 처리
  if (name != null){
    return name.toUpperCase();
  }
  return 'ANON';
}

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

// QQ operator 사용
// left ?? right
// left 항이 true 이면 left 항 진행하고 left 항이 false면 right 항 진행
String capitalizename_3(String? name)
  => name?.toUpperCase() ?? 'ANON';

void main(){
  capitalizeName('jh');
  capitalizeName(null);
  
  capitalizeName_2('jh');
}
  • ?=: 만약에 null 이라면 오른쪽 값을 넣어라
void main(){
  String? name;
  name ??= 'jh';
  print(name);
}

3.5 Typedef

  • typedef: 자료형이 헷갈릴 때 도움이 될 alias을 만드는 방법
typedef ListOfInts = List<int>; // 자료형 정의
typedef UserInfo = Map<String, String>;

String sayHi(Map<String, String> userInfo){
  return "Hi ${userInfo['name']}";
}

ListOfInts reversListOfNumbers(ListOfInts list){
  var reversed = list.reversed;
  return reversed.toList(); // list로 변환
}

void main(){
  print(reversListOfNumbers([1,2,3]));
  print(sayHi({"name":'jh'}));
}

4. CLASSES

4.0 Your First Dart Class

  • Dart class 선언
class Player{ // class 내부에서는 타입 명시 
  final String name = 'jh';
  int xp = 1500;
  
  void sayHello(){
    var name = 'abc';
    print('Hi my name is $name'); // name이 중복이 없다면 이대로 사용 가능하지만
    print("Hi ny name is ${this.name}"); // 중복되면 this를 추가해야 함
  }
}

void main(){
  var player = Player(); // 인스턴스 하나 생성
  print(player.name);
  // player.name = 'sdf'; // final이 없을 때만 수정 가능
  player.sayHello();
}

4.1 Constructors

  • 초기화 함수 생성
  • constructors method는 class와 반드시 이름이 같아야 함
class Player{ // class 내부에서는 타입 명시 
  late final String name;
  late int xp;
  
  Player(String name, int xp){ // constructor method 이름은 class 이름과 같아야 함
    this.name = name;
    this.xp = xp;
  }
  
  void sayHello(){
    print("Hi ny name is ${name}"); // 중복되면 this를 추가해야 함
  }
}

// 조금 더 코드를 깔끔하게 정리
class Player2{ // class 내부에서는 타입 명시 
  final String name;
  int xp;
  Player2(this.name, this.xp);
  
  
  void sayHello(){
    print("Hi ny name is $name"); // 중복되면 this를 추가해야 함
  }
}

void main() {
  var player = Player('jh',1234); // 인스턴스 하나 생성
  player.sayHello();
  var player2 = Player('lynn', 12123);
  player2.sayHello();
}

4.2 Named Constructor Parameters

  • Named constructor parameters는 말 그대로 파라미터에 이름을 붙여주는 것이다.
  • 위 constructor에서는 단순히 positional parameters 이기 때문에 순서 정보에 맞추어 파라미터를 입력해야 한다 -> 파라미터가 많아지면 어려워지겠지?
  • 이를 해결하기 위해 파라미터를 딕셔너리로 묶어서 입력 받기
class Player{
  // 1. type 선언
  final String name;
  int xp;
  String team;
  int age;
  
  // 2. constructor
  Player({required this.name, 
          required this.xp, 
          required this.team, 
          required this.age});
  
  void sayHello(){
    print("Hi my name is $name");
  }
}

void main(){
  var player = Player(
    name:'nico',
    xp:1200,
    team:'blue',
    age:21,
  );
  
  var player2 = Player(
    name:'lynn',
    xp:2500,
    team:'blue',
    age:12,
  );
}

4.3 Named Constructor

  • 위에서 작성한 Named constructor parameters는 모든 파라미터를 다 넣어줘야 함
  • 그래서 모든 파라미터를 다 넣지 않고 일부 필요한 것만 받기 위해서 : 를 사용하여 초기화를 진행
class Player{
  // 1. type 선언
  final String name;
  int xp, age ;
  String team;
  
  // 2. constructor
  Player({required this.name, 
          required this.xp, 
          required this.team, 
          required this.age});
  
  void sayHello(){
    print("Hi my name is $name");
  }
  
  Player.createBluePlayer({required String name,
                          required int age}): // :은 player 클래스를 초기화하는 일
  this.age = age,
  this.name = name,
  this.team = 'blue',
  this.xp = 0;
  
  Player.createRedPlayer({required String name,
                         required int age}):
  this.age = age,
  this.name = name,
  this.team = 'red',
  this.xp = 0;
}

void main(){
  var player = Player.createBluePlayer(
    name:'nico',
    age:21,
  );
  
  var redplayer = Player.createRedPlayer(
    name:'lynn',
    age:12,
  );
}

4.4 Recap

class Player{
  // 1. type 선언
  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");
  }
  
  
}

void main(){
  var apiData = [
    {
      'name':'nico',
      'team':'red',
      'xp':0,
    },
    {
      'name':'lynn',
      'team':'red',
      'xp':0,
    },
    {
      'name':'dal',
      'team':'red',
      'xp':0,
    }
  ];
  apiData.forEach((playerJson){
    var player = Player.fromJson(playerJson);
    player.sayHello();
  });
}

4.5 Cascade Notation

  • constructor로 호출하고 값을 수정할 때 조금 더 쉬운 코드가 있음
class Player{
  // 1. type 선언
  String name;
  int xp ;
  String team;
  
  Player({required this.name,
         required this.xp,
         required this.team});
  
  void sayHello(){
    print("Hi my name is $name");
  }
  
  
}

void main(){
  // constructor로 생성하고 값을 수정할 때 다음과 같이 수정함
  var jh = Player(name:'jh', xp:1200, team:'blue');
  jh.name = 'another';
  jh.xp = 123182309;
  jh.team = 'red';
  
  // Cascade Notation
  // 그러나 위와 같은 코드를 아래처럼 수정할 수 있음. 훨씬 더 간편함
  var nico = Player(name: 'jh', xp:1200, team:'red')
    ..name = 'las'
    ..xp = 120000
    ..team = 'blue'
    ..sayHello();
  
}

4.6 Enums

  • 만약 내가 클래스에 특정 변수가 String 형태의 색상을 받는 부분을 작성한다고 할 때, red를 redd 이런 식으로 오타가 날 수 있다.
  • 이를 방지하고자 enum을 사용해서 'red','blue' 이런 식으로 들어갈 수 있는 값을 미리 정해줘서 오타를 사전에 방지할 수 있는 좋은 기능
enum Team { red, blue }
enum XPLevel {beginner, medium, pro}

class Player{
  // 1. type 선언
  String name;
  XPLevel xp ;
  Team team;
  
  Player({required this.name,
         required this.xp,
         required this.team});
  
  void sayHello(){
    print("Hi my name is $name");
  }
  
  
}

void main(){
  // constructor로 생성하고 값을 수정할 때 다음과 같이 수정함
  var jh = Player(name:'jh', xp:XPLevel.medium, team:Team.red);
  jh.name = 'another';
  jh.xp = XPLevel.beginner;
  jh.team = Team.red;
  
  // Cascade Notation
  // 그러나 위와 같은 코드를 아래처럼 수정할 수 있음. 훨씬 더 간편함
  var nico = Player(name: 'jh', xp:XPLevel.beginner, team:Team.blue)
    ..name = 'las'
    ..xp = XPLevel.pro
    ..team = Team.blue
    ..sayHello();
  
}

4.7 Abstract Classes

  • 추상화 클래스: 다른 클래스들이 직접 구현해야 하는 메소들을 모아 놓은 청사진
  • 추상화 클래스를 상속받으면 추상화 클래스에서 모아놓은 메소드를 구현해야 함
// 추상화 클래스: 다른 클래스들이 직접 구현해야 하는 메소드들을 모아놓은 일정의 청사진
abstract class Human{
  void walk(); 
  // Human이라는 추상화 클래스는 walk라는 메소드를 가지고
  // return이 없는 void 이다 정도 정의해줌 -> 일종의 청사진
}

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

class Player extends Human{ // extends: 상속
  // 1. type 선언
  String name;
  XPLevel xp ;
  Team team;
  
  Player({required this.name,
         required this.xp,
         required this.team});
  
  void walk(){
    print("im walking");
  }
  void sayHello(){
    print("Hi my name is $name");
  }
  
  
}

class Coach extends Human{
  void walk(){
    print("the coach i walking");
  }
}
void main(){
  // constructor로 생성하고 값을 수정할 때 다음과 같이 수정함
  var jh = Player(name:'jh', xp:XPLevel.medium, team:Team.red);
  jh.name = 'another';
  jh.xp = XPLevel.beginner;
  jh.team = Team.red;
  
  // Cascade Notation
  // 그러나 위와 같은 코드를 아래처럼 수정할 수 있음. 훨씬 더 간편함
  var nico = Player(name: 'jh', xp:XPLevel.beginner, team:Team.blue)
    ..name = 'las'
    ..xp = XPLevel.pro
    ..team = Team.blue
    ..sayHello();
  
}

4.8 Inheritance

  • 상속(역시 상속 개념 쉽지 않다.)
    • 부모 클래스가 Human, 자식 클래스가 Player
    • 여기서 Player constructor는 반드시 super를 사용해서 Human constructor를 호출해야 함
    • 그리고 Human에서 작성된 메소드를 커스터마이징 하고 싶다면 @override를 사용하여 수정할 수 있음 -> 부모 클래스에 정의된 함수에서 조금 추가하고 싶다면 super.함수명()으로 호출한 다음 커스터 마이징 코드를 작성하면 됨
class Human{
  final String name;
  Human({required this.name});
  
  void sayHello(){
    print('Hi my name is $name');
  }
}

enum Team { blue, red}
class Player extends Human{
  final Team team;
  
  Player({
    required this.team,
    required String name
  }): super(name: name); // super라는 키워드를 통해 부모 클래스와 상호작용 가능
  
  @override
  void sayHello(){
    super.sayHello();
    print('and i play for ${team}');
  }
  
  
}

void main(){
  var player = Player(team: Team.red, name: 'nico');
  player.sayHello();
}

4.9 Mixins

  • Mixins: 생성자가 없는 클래스
  • 부모 클래스를 extends로 상속을 받았다면 Mixins은 with로 가져옴.
  • Mixins의 장점으로는 여러 번 재사용이 가능하다!
  • mixin class로 시작해주면 됨
mixin class Strong{ // 생성자가 없음
  final double strengthLevel = 1500.99;
}

mixin class QuickRunner{ // 생성자가 없음
  void runQuick(){
    print("ruuuuuuuuun!");
  }
}

mixin class Tall{ // 생성자가 없음
  final double height = 1.99;
}

class Horse with Strong, QuickRunner{}
class Kid with QuickRunner{}


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

enum Team { blue, red}
class Player with  Strong, QuickRunner, Tall{
  final Team team;
  
  Player({
    required this.team,
    required String name
  });
  
}

void main(){
  var player = Player(team: Team.red, name: 'nico');
  player.height; // mixin class 에서 선언한 값에 접근 가능
 
}

4.10 Conclusions

dart 베이스 지식 공부 완료!

Dart 강의 출처: 노마드 코더

0개의 댓글