[Dart] 안전한 유효 코드를 작성하는 Generics(총칭형) 기반

40456 단어 FlutterDarttech

[Dart] Generics(총칭)


개시하다


  • [참고] 공식 사이트
  • Language tour | Dart > Generics

  • Generics(총칭)는
  • 활용 목적
  • 특정 유형을 기재하지 않고 임시로 총칭형을 설치한 후 결정
  • 이점
  • 중복 제거 코드
  • 서로 다른 유형의 변수를 대입하면 컴파일 오류로 알려 줍니다

  • 운영 환경

  • DartPad 및 Android Studio 등
  • Dart SDK 2.10.4
  • Generics를 사용하지 않는 경우

  • String 변수가 있는 User 클래스
  • 이미지: 가게와 병원의 호출명은 이름(문자열)
  • class User {
      final String callName;
      User(this.callName);
    }
    
    void main() {
      final user = User('Tanaka');
      print(user.callName);
    }
    
    실행 결과
    Tanaka
    
  • int 변수가 있는 User 클래스
  • 상기 코드가 먼저 존재하는 상황에서 클래스를 변경하고 이름을 바꾸어 여러 개를 만들어야 한다
  • 이미지: 가게와 병원의 번호는 번호(숫자)
  • class User {
      final int callName;
      User(this.callName);
    }
    
    void main() {
      final user = User(1);
      print(user.callName);
    }
    
    실행 결과
    1
    
  • dynamic 변수가 있는 User 클래스
  • dynamic callName인 경우 문자열을 사용할 수 있습니다.
  • final callName로 기재되면callName은dynamic형
  • class User {
      final callName;
      User(this.callName);
    }
    
    void main() {
      final user = User('Tanaka');
      print(user.callName);
    }
    
    실행 결과
    Tanaka
    
  • dynamic 변수가 있는 User 클래스
  • dynamic callName면 숫자도 받을 수 있다
  • class User {
      final callName;
      User(this.callName);
    }
    
    void main() {
      final user = User(1);
      print(user.callName);
    }
    
    실행 결과
    1
    
  • dynamic 변수는 편리하지만 실행 중 오류가 발생해도 알 수 있는 오류가 발생할 수 있습니다
  • 오류의 예
  • dynamic callName에서 int가 값을 만든 후 String의 변수를 대입하려면 컴파일 오류가 발생하지 않고 실행 중 오류가 됩니다
  • 오류가 발생하지 않도록 다음과 같은 등을 진행할 수 있으나 잊어버리면 실행 중 오류가 발생하여 위험합니다
  • String name = user.callName.toString();
  • class User {
      final callName;
      User(this.callName);
    }
    
    void main() {
      final user = User(1);
      print(user.callName);
      String name = user.callName;
    }
    
    실행 결과
    1
    Uncaught Error: TypeError: 1: type 'JSInt' is not a subtype of type 'String'
    

    Generics 사용 시

  • Generics가 있는 User 클래스
  • 컴파일 오류(IDE 알려줌)
  • String name = user.callName;에서 다음 오류가 발생했습니다.
  • A value of type 'int' can't be assigned to a variable of type 'String'
  • class User<T> {
      final T callName;
      User(this.callName);
    }
    
    void main() {
      final user = User(1);
      print(user.callName);
      String name = user.callName;
    }
    
    실행 결과
    Error compiling to JavaScript:
    main.dart:9:22:
    Error: A value of type 'int' can't be assigned to a variable of type 'String'.
      String name = user.callName;
                         ^
    Error: Compilation failed.
    
  • Generics가 있는 User 클래스
  • T callName인 경우 문자열
  • 이 있습니다.
    class User<T> {
      final T callName;
      User(this.callName);
    }
    
    void main() {
      final user = User('Tanaka');
      print(user.callName);
    }
    
    실행 결과
    Tanaka
    
  • Generics가 있는 User 클래스
  • T callName면 숫자도 받을 수 있다
  • 범주를 재작성하지 않고도 여러 유형을 안전하게 활용할 수 있음
  • class User<T> {
      final T callName;
      User(this.callName);
    }
    
    void main() {
      final user = User(1);
      print(user.callName);
    }
    
    실행 결과
    1
    
  • [비고]<T><TEST>
  • 습관상 주요 이용T
  • class User<Test> {
      final Test callName;
      User(this.callName);
    }
    
    void main() {
      final user = User('Tanaka');
      print(user.callName);
    }
    
    실행 결과
    Tanaka
    
  • 명확한 기재 유형

  • 설정User<String>('Tanaka') 또는 User<int>(1)을 통해 Generic
  • 를 쉽게 이해할 수 있습니다.
    class User<T> {
      final T callName;
      User(this.callName);
    }
    
    void main() {
      final user = User<String>('Tanaka');
      print(user.callName);
    }
    
    실행 결과
    Tanaka
    

    Generics 계층 구조

  • Generics를 가진 클래스를 계승
  • 주의
  • 일치하는 수퍼 클래스Generics의 이름
  • class SingleUser<A> extends User<T> {}시 다음 오류 발생
  • The name 'T' isn't a type so it can't be used as a type argument
  • 슈퍼 클래스의 지정은 뒤에 있는 <T>까지 해야 한다.
  • extends User<T>가 아니라extends Useruser1.callNamedynamic형으로 변한다
    = 다른 유형의 변수를 대입해도 컴파일 오류로 알려주지 않음
  • abstract class User<T> {
      final T callName;
      User(this.callName);
    
      void call();
    }
    
    class SingleUser<T> extends User<T> {
      SingleUser(T callName) : super(callName);
    
      void call() {
        print('call SingleUser');
        print(callName);
      }
    }
    
    class MultiUser<T, K> extends User<T> {
      final K callNamePlus;
      MultiUser(T callName, this.callNamePlus) : super(callName);
    
      void call() {
        print('call MultiUser');
        print(callName);
        print(callNamePlus);
      }
    }
    
    void main() {
      final user1 = SingleUser<String>('Tanaka');
      user1.call();
      final user2 = MultiUser<int, String>(1, 'Tanaka');
      user2.call();
    }
    
    실행 결과
    call SingleUser
    Tanaka
    call MultiUser
    1
    Tanaka
    
  • Generics가 있는 클래스의 시간 제한 유형을 계승하는 경우
  • User<T extends num> 지정 숫자(int or double)
  • int와 더블은num의 하위 클래스입니다(자세한 내용은 아래와 같습니다)

  • dart:core library - Dart API
  • num class - dart:core library - Dart API
  • 문자열로 제한된 경우T extends String
  • abstract class User<T extends num> {
      final T callName;
      User(this.callName);
    
      void call();
    }
    
    class SingleUser<T extends num> extends User<T> {
      SingleUser(T callName) : super(callName);
    
      void call() {
        print('call SingleUser');
        print(callName);
      }
    }
    
    class MultiUser<T extends num, K> extends User<T> {
      final K callNamePlus;
      MultiUser(T callName, this.callNamePlus) : super(callName);
    
      void call() {
        print('call MultiUser');
        print(callName);
        print(callNamePlus);
      }
    }
    
    void main() {
      final user1 = SingleUser<int>(1);
      user1.call();
      final user2 = MultiUser<int, String>(2, 'Tanaka');
      user2.call();
    }
    
    실행 결과
    call SingleUser
    1
    call MultiUser
    2
    Tanaka
    

    Generics 함수

  • T(TEST 등도 가능하지만 관례에 따라 T 또는 K)를 반환값으로 쓴다
  • T를 매개 변수로 하고 T의 함수를 되돌려줍니다
  • T myself<T>(T name) => name;
  • T를 매개 변수로 처리하는 방법
  • void check<T>(T val) {}
  • 비고
  • Generics를 이용한 클래스가 아니어도 가능
  • 상세 예: sdk/GENERIC_METHODS.md at master · dart-lang/sdk
  • abstract class User<T extends num> {
      final T callName;
      User(this.callName);
    
      // Generics methods
      T myself<T>(T name) => name;
      
      void check<T>(T val) {
        print('型名は以下');
        print(T);
        print(val);
      }
    }
    
    class MultiUser<T extends num, K> extends User<T> {
      final K callNamePlus;
      MultiUser(T callName, this.callNamePlus) : super(callName);
    }
    
    void main() {
      final user = MultiUser<int, String>(2, 'Tanaka');
      final int userNameInt = user.myself<int>(user.callName);
      final String userNameString = user.myself<String>(user.callNamePlus);
      print(userNameInt);
      print(userNameString);
      user.check<int>(user.callName);
      user.check<String>(user.callNamePlus);
    }
    
    실행 결과
    2
    Tanaka
    型名は以下
    int
    2
    型名は以下
    String
    Tanaka
    

    좋은 웹페이지 즐겨찾기