8 분 소요

✨ 외부 패키지 사용하기

  • pub.dev 사이트
    • PLATFORM 호환 종류 확인
    • Null safety 명시 확인 → 적용 개발 확인하기
  • 외부 패키지 사용방법
    1. pubspec.ymal, 패키지와 버전을 명시 후 Pub get
    2. 터미널을 통해 ‘flutter pub add [패키지명]’ 입력
  • 추가 결과 : pubspec.ymal에 추가되어있음
      dependencies:
          flutter:
              sdk: flutter
          cupertino_icons: ^1.0.2
          english_words: ^4.0.0
      dev_dependencies:
          flutter_test:
          sdk: flutter
    
  • 대부분의 패키지는 dependencies에 등록
  • 앱 개발때만 이용하느 패키지는 dev_dependencies에 등록
    • 패키지 이름과 버전을 명시(^는 지정되는 버전과 호환되는 모든 범위의 버전)
  • 다트 엔진 라이브러리(의존성 설정 필요X)
플랫폼 종류 라이브러리 종류 지원하는 내용
멀티 플랫폼 dart:async 비동기 프로그래밍
  dart:collection LinkedList, HashMap 등 집합 데이터
  dart:convert JSON 같은 데이터의 인코딩과 디코딩
  dart:core 내장(built-in) 타입, 컬렉션 등
  dart:developer 디버거나 인스펙터 등 개발자 도구
  dart:math 수학 함수
네이티브 플랫폼 dart:io 파일, 소켓, HTTP 등 앱에서 발생하는 입출력
  dart:isolate 동시성 프로그래밍(일종의 스레드 프로그래밍)
웹 플랫폼 dart:html HTML 요소
  dart:indexed_db 키-값 형태의 데이터 저장
  dart:web_audio 오디오 핸들링
  dart:web_gl 3D 그래픽
  dart:web_sql SQL 기반 데이터 저장

1. 다트 기본기능 알아보기

1) 선언, 라이브러리 불러오기

  • 변수/함수/클래스 선언
      int no = 10;
    	
      void sayHello() {
          print('hello, $no');
      }
    	
      class User{
          int no = 10;
    	
          void sayHello() {
              print('world, $no');
          }
      }
    
  • 상대 경로로 불러오기
    • 같은 프로젝트에 있는 다른 다트 파일 불러올 때
        import '../outer_folder/outer_main.dart';
      
  • package 접두사 불러오기
      import 'package : [패키지 이름]';
      import 'package :[다트 파일 이름].dart';
    
  • dart 접두사로 불러오기
      import 'dart:core';
      import 'dart:async';
    

2) 외부에서 사용할 수 없게 제한하기

  • public vs private (접근 제한자)
      no1 = 20; // public
      _no2 = 30; // private
    

3) 식별자에 별칭 정의하기

  • as 예약어
      import 'test1.dart' as Test1;
    
      main() {
          no1 = 30;  // 오류
          Test1.no1 = 30;
    
          Test1.sayHello1();
          Test1.User1 user1 = Test1.User1();
      }
    

4) 특정 요소민 불러오기

  • show
      import 'test1.dart' show no1, User1;
    	
      main() {
          no1 = 30;
          User1 user1 = User1(); // 클래스 선언 문법(클래스명 / 객체명 = 클래스명)
    	
          sayHello1(); // 오류
      }
    
    • int, double처럼 class를 가져오기에 앞에 클래스명을 붙여주어야 한다.

5) 특정 요소 제거한 채 불러오기

  • hide
      import `test1.dart` hide sayHello1, User1;
    	
      main() {
          no1 = 30;
          sayHello1();   // 오류
          User1 user1 = User1();   // 오류
      }
    

2. 라이브러리 만들기

1) 여러 파일을 하나로 묶어 import 하는 법

  • 예시 : a.dart, b.dart파일을 myLib.dart파일로 묶어 사용하는 법
      // a.dart
      part of my_lib;
      int aData = 10;
    
      // b.dart
      part of my_lib;
      int bData = 20;
    
      // myLib.dart
      library my_lib;
      part 'a.dart';
      part 'b.dart';
    
  • 불러오기
      import 'myLib.dart';
    	
      main(){
          print('$aData, $bData');
      }
    

3. 데이터 타입과 널 안정성

1) 데이터 타입

  • 타입 클래스
라이브러리 타입 클래스 데이터
dart:core bool true, false
  double 실수
  int 정수
  num 숫자(double과 int의 상위 클래스)
  String 문자열
dart:typed_data ByteData 바이트
  • 문자열 표현하기 : ‘ / “ / ‘’’ / “””
      main() {
          String data1 = 'hello';
          String data2 = 'world';
          String data3 = '''
              hello
              world
          ''';
          String data4 = """
              hello
              world
          """;
      }
    
  • 문자열 비교 : == / bool(true, false)
      String str1 = 'hello';
      String str2 = 'hello';
    
      print(str1 == str2)
    
  • 문자열 템플릿 : $
      main() {
          int no = 10;
          String name = 'kkang'
    	
          String myFun() {
              return 'kim';
          }
    	
          print('no : $no, name : $name, 10 + 20 : ${10 + 20}, myFun() : ${myFun()}')
      }
    
  • 형 변환하기
      main() {
          int n1 = 10;
          double d1 = 10.0;
    
          double d2 = n1;  // 오류
          int n2 = d1;  // 오류
    
          double d2 = n1.toDouble();  // 성공(int → double)
          int n2 = d1.toInt();  // 성공(double → int)
      }
    
      main() {
          int n1 = 10;
          String s1 = '10';
    
          String s2 = n1.toString();  // 성공(int → String)
          int n3 = int.parse(s1);  // 성공(String → int)
      }
    

2) 상수 변수 - const, final

  • 상수 변수란? 초기값을 대입한 후에 값을 바꿀 수 없는 변수

(1) Const : 컴파일 타임 상수 변수

  • 초기값 대입 시점은 선언문 / 변숫값 변경할 시 오류
  • 클래스 내부 선언 시 static
      const String data1;  // 오류
      const String data2 = 'hello';
    	
      class User {
          static const String data3 = 'hello'
    	
          void some() {
              const String data4 = 'hello';
    	
              data2 = 'world';  // 오류
              data3 = 'world';  // 오류
              data4 = 'world';  // 오류
          }
      }
    

(2) final : 런 타임 상수 변수

  • 초깃값을 대입 시점은 선언문 / 변숫값 변경할 시 오류
      final int no1;  // 초깃값이나 이후에 값을 대입하지 않아서 오류
    	
      class MyClass
          final int no2;
          MyClass(this.no2);
    	
          void some() {
              final no3;
              no3 = 10;
              no3 = 20;  // 값을 바꿀 수 없어서 오류
          }
    
  • MyClass(this.no2) def –init–이랑 비슷하다.

(3) 상수 변수와 문자열 템플릿

main() {
	String s1 = 'hello';
	const String s2 = 'world';
	final String s3 = 'helloworld';
	
	String s4 = '$s1, $s2';
	const String s5 = '$s2';
	const String s6 = '$s1, $s2, $s3';  // 오류
	final String s7 = '$s1, $s2, $s3';
}

3) 선언 - var와 dynamic

(1) var : 타입 유추 / 타입 결정됨

var no = 10;
no = 20;   // int로 결정
no = 'hello';  // 오류

(2) dynamic : 모든 타입의 데이터 대입 가능

dynamic data = 10;
data = 'hello';
data = true;

4) 컬렉션 - List, Set, Map

(1) List

  • List 타입 미지정
      main() {
          List List1 = [10, 'hello', true];
          list1[0] = 20;
          list1[1] = 'world';
          print('List : [${list1[0]}, ${list1[1]}, ${list1[2]}');
      }
    
  • List 타입 지정
      main() {
          List<int> list2 = [10, 20, 30]
          list2[0] = 'hello'; // 오류
      }
    
  • List 요소 추가/제거
      main() {
          List<int> list2 = [10, 20, 30];
          print(list2);  // [10, 20, 30]
    	
          list2.add(40);  // 추가
          list2.add(50);  // 추가
          print(list2);  // [10, 20, 30, 40, 50]
    	
          list2.removeAt(0);  // 제거, 인덱스
          print(list2);  // [20, 30, 40, 50]]
      }
    
  • List 크기 지정
      main() {
          var list3 = List<int>.filled(3, 0);
          print(list3);  // [0,0,0]
    	
          list3[0] = 10;
          list3[1] = 20;
          list3[2] = 30;
          print(list3);  // [10,20,30]
    	
          list3.add(40);  // 오류
      }
    
    • 확장 가능하게 하기
        main() {
            var list3 = List<int>.filled(3, 0, growable: true);
            print(list3);  // [0,0,0]
      		
            list3[0] = 10;
            list3[1] = 20;
            list3[2] = 30;
            print(list3);  // [10,20,30]
      		
            list3.add(40);
            print(list3);  // [10,20,30, 0]
        }
      
  • 로직을 통해 List 선언 : <예시> index * 10
      main() {
          var list4 = List<int>.generate(3, (index) => index * 10, growable: true);
          print(list4);  // [0, 10, 20]
      }
    

(2) 집합 타입

  • list + <중복 미허용="">

  • set 타입 지정

      main() {
          Set<int> set1 = {10, 20, 30};
          print(set1);  // {10, 20}
          set1.add(30);
          set1.add(40);
          print(set1);  // {10, 20, 30, 40}
    	
          Set<int> set2 = Set();
          set1.add(10);
          set1.add(20);
          print(set2);  // {10, 20}
      }
    

(3) 맵 타입

  • 키, 값 형태(Python dictionary)
    main() {
      Map<String, String> map1 = {'one':'hello', 'two':'world'};
    
      print(map1['one']);  // 'hello'
      map1['one'] = 'world';
      print(map1['one']);  // 'world'
    }
    

5) 널 포인트 예외 관리하기

  • 정의 : 널 포인트 예외(NPE:null point exception)를 코드 작성 시점에서 점검하는 것
    • 널 포인트 예외(NPE:null point exception) : 객체가 null이어서 발생하는 오류

(1) 널 허용과 널 불허

  • 널 허용, 널 불허 설정(기본값 : 널 불허)
      // int
      int a1 = 10;  // null 불허
      int? a2 = 10;  // null 허용
    	
      testFun() {
          a1 = null;  // 오류
          a2 = null;
      }
    
      // string
      String str1 = null;  // 오류
      String? str1 = null;
    	
      // class
      clear User{ }
      User user1 = null;  // 오류
      User? user2 = null;
    

(2) 널 불허 변수의 초기화

  • 탑/클래스 내부(초기화 필수), 함수 내부(가능)
      int a1;  // 오류(초기화 해야됨)
    	
      class User {
          int a1; // 오류(초기화 해야됨)
      }
    	
      testFun() {
          int a1;   // 성공(초기화 하지 않아도 됨)
          a1 = null;  // 오류
      }
    
  • 함수 내부(사용하기 전 반드시 값 대입해주어야 함)
      testFun() {
          int a1;
          print(a1 + 10); // 오류
    
          int a2;
          a2 = 10;
          print(a2 + 10);  // 성공
      }
    

(3) var 타입의 널 안정성

  • var 타입의 널 안정성(널 불가 : 타입 유추)
      main() {
          var a1 = 10;  // int
          var a2 = null;   // dynamic
          var a3;          // dynamic
          var? a4 = null;  // 오류
      }
    
      int no1 = 10;  // 널 불허
      int? no2;    // 널 허용
    	
      var a1 = no1;  // int로 결정
      var a1 = no2;  // int?로 결정
    	
      testFun() {
          a1 = 20;
          a1 = null;  // 널 불허 변수에 널을 대입해서 오류
    	
          a2 = 20;
          a2 = "hello";   // int? 타입에 문자열을 대입해서 오류
          a2 = null;
      }
    

(4) dynamic 타입의 널 안정성

  • dynamic 타입의 널 안정성(널 허용 : 모든 값 허용)
      dynamic a1 = 10;
      dynamic a2;
      dynamic? a3;
    	
      testFun() {
          a1 = null;
          a2 = null;
          a3 = null;
      }
    

(5) 널 안정성과 형 변환 - ?, as

  • int? > int {널 허용[Nullable] > 널 불허[NonNull]}
      int a1 = 10;
      int? a2 = 10;
    	
      main() {
          a1 = a2;  // 오류
          a2 = a1;  // 성공
      }
    
  • 명시적 형 변환
      int a1 = 10;
      int? a2 = 20;
    	
      main() {
          a1 = a2 as int;
          print("a1: $a1, a2: $a2");  // a1: 20, a2:20
      }
    

(6) 초기화를 미루는 연산자 - late

  • late(초기화 미루기)
      int a1;  // 컴파일 오류
      late int a2;  // 성공
    
      late int a2;   // 성공
    	
      main() {
          print('${a2 + 10}');  // 오류
    	
          a2 = 10;
          print('${a2 + 10}');  // 성공
      }
    

6) 널 안정성 연산자

(1) 널 판단 - !

  • null시 런 타임 오류 발생
      int? a1 = 20;
    	
      main() {
          a1!;
          a1 = null;
          a1!;  // 런 타임 오류
      }
    
      int? some(arg) {
          if ( arg == 10 ) {
              return 0;
              } else {
              return null;
              }
      }
    	
      main() {
          int a = some(10)!;
          print('a : $a');    // a : 0
          int b = some(20)!;   // some() 함수가 널을 반환하므로 런 타임 오류
          print('b : $b');
      }
    

(2) 널 허용 객체의 접근 - ?. / ?[]

  • isEmpty - ?
      String? str = "hello";
    	
      main() {
          str.isEmpty;  // 오류
          str?.isEmpty;
      }
    
  • isEven - ?
      main() {
          int? no1 = 10;
          bool? result1 = no1?.isEven;
          print('result 1 : $result1');  // true
    	
          no1 = null;
          bool? result2 = no1?.isEven;
          print('result 2 : $result2');  // null
      }
    
  • 널 리스트 접근할 때 - ?[]
      main() {
          List<int>? list = [10, 20, 30];
          print('list[0] : ${list?[0]}');  // 10
          list = null;
          print('list[0] : ${list?[0]}');  // null
      }
    

(3) Null이 아닌 값만을 대입할 때 - ??=

  • Null이 아닌 값만을 대입할 때 - ??=
      main() {
          int? data3;
          data3 ??= 10;
          print('data3 : $data3');  // 10
          data3 ??= null;
          print('data3 : $data3');  // 10(Null이라 대입 안됨)
      }
    

(4) Null인 값을 대체할 때 - ??

  • Null인 값을 대체할 때 - ??
      String? data4 = 'hello';
      String? result = data4 ?? 'world';   // hello
      print('result : $result');
    	
      data4 = null;
      result = data4 ?? 'world';   // world
      print('result : $result');
    

댓글남기기