Generics


Generics


なぜGenerics構文が必要なのですか?

// 제네릭이라는 문법의 필요성 알아보기

// 정수 2개

var num1 = 10
var num2 = 20



// 두 숫자를 스왑(서로 교환)하는 함수의 정의
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let tempA = a
    a = b
    b = tempA
}



// 위에서 정의한 함수의 실행
swapTwoInts(&num1, &num2)

print(num1)
print(num2)



// 만약, Double을 교환하고 싶다면?, String을 교환하고 싶다면?


// Double을 스왑하는 함수의 정의

func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
    let tempA = a
    a = b
    b = tempA
}



// (정수가 아닌) 문자열을 스왑하는 함수의 정의

func swapTwoStrings(_ a: inout String, _ b: inout String) {
    let tempA = a
    a = b
    b = tempA
}
  • Generickがない場合、各関数(クラス、構造体、列挙型など)タイプはすべての状況を定義する必要があるため、
  • .
  • 開発者の仕事が増えます.
  • (メンテナンス/再使用性の観点からは難しい)
    Genericsの概念がない場合は、すべての場合に関数を再定義する必要があります.
  • Jeneric構文
  • のフォーマットにかかわらず、すべてのタイプを一度に実装するだけで処理することができ、タイプに柔軟な関数(メンテナンス/再利用性が向上)
  • を作成することができる.
  • (関数を含まない)構造体/クラス/列挙型図、汎用
  • 型パラメータは、関数においてパラメータフォーマットまたはコールバック(関数本体でも使用可能)として使用する
  • である.
  • は通常Tを使用しますが、他の名前を使用しても問題ありません.フォーマット名であるため、UpperCamelcase
  • と宣言します.
  • 2賞を発表したのも
  • かもしれない.
  • Generickは、任意のタイプ(データ)を定義(実装)で処理できる構文
  • です.
  • Jenny関数、Jenny構造体/クラス
  • の通常の関数と比較して、記述する必要があるコードの数は
  • 減少した.
  • タイプのパラメータは、新しいフォーマットを生成する
  • ではありません(任意のシンボルに類似)===>
  • コードを実行すると、コンテキストに応じて実際のフォーマットに置き換えられる「プレースホルダ」にすぎません.

    ジェニーリック関数の定義

    // 파라미터의 타입에 구애받지 않는 일반적인(제네릭) 타입을 정의
    
    func swapTwoValues<T>(_ a: inout T, _ b: inout T) {      // 플레이스홀더의 역할(표시 역할일뿐) (같은 타입이어야함)
        let tempA = a
        a = b
        b = tempA
    }
    
    
    
    var string1 = "hello"
    var string2 = "world"
    
    
    
    // 제네릭으로 정의한 함수 사용해보기
    
    swapTwoValues(&string1, &string2)     // 같은 타입이라면, 어떠한 값도 전달 가능 해짐
    print(string1)
    print(string2)
    
    
    
    
    
    // 배열을 출력하는 예제
    
    func printArray<T>(array: [T]) {
        for element in array {
            print(element)
        }
    }
    
    
    printArray(array: numbers)     // 플레이스홀더 ====> [Int]
    printArray(array: scores)      // 플레이스홀더 ====> [Double]
    printArray(array: people)      // 플레이스홀더 ====> [String]

    ジェニーリックタイプの定義


    Generics構造/クラス/(列挙)
    struct Member {
        var members: [String] = []
    }
    
    
    
    struct GenericMember<T> {
        var members: [T] = []
    }
    
    
    
    var member1 = GenericMember(members: ["Jobs", "Cook", "Musk"])
    var member2 = GenericMember(members: [1, 2, 3])
    
    
    
    
    // 클래스로 제네릭의 정의하기
    
    class GridPoint<A> {
        var x: A
        var y: A
        
        init(x: A, y: A){
            self.x = x
            self.y = y
        }
    }
    
    
    let aPoint = GridPoint(x: 10, y: 20)
    let bPoint = GridPoint(x: 10.4, y: 20.5)
    
    
    
    
    // 열거형에서 연관값을 가질때 제네릭으로 정의가능
    // (어짜피 케이스는 자체가 선택항목 중에 하나일뿐(특별타입)이고, 
    그것을 타입으로 정의할 일은 없음)
    
    enum Pet<T> {
        case dog
        case cat
        case etc(T)
    }
    
    
    
    let animal = Pet.etc("고슴도치")

    Generics構造体の拡張

    // 정의
    
    struct Coordinates<T> {
        var x: T
        var y: T
    }
    
    
    
    // 제네릭을 Extension(확장)에도 적용할 수 있다. (확장 대상을 제한하는 것도 가능은 함)
    
    extension Coordinates {     // Coordinates<T> (X)
        
        // 튜플로 리턴하는 메서드
        func getPlace() -> (T, T) {
            return (x, y)
        }
    }
    
    
    let place = Coordinates(x: 5, y: 5)
    print(place.getPlace())
    
    
    
    
    // where절 추가도 가능
    // Int타입에만 적용되는 확장과 getIntArray() 메서드
    
    extension Coordinates where T == Int {     // Coordinates<T> (X)
        
        // 튜플로 리턴하는 메서드
        func getIntArray() -> [T] {
            return [x, y]
        }
    }
    
    
    let place2 = Coordinates(x: 3, y: 5)
    place2.getIntArray()
    
    
    
    
    //let place3 = Coordinates(x: 3.5, y: 2.5)
    //place3.getIntArray()

    タイプコンストレイント

  • ジュネーブではタイプ
  • を制限できます.
  • 型パラメータ名の後にコロンが付いた「プロトコル」制約または「単一クラス」
  • (1)プロトコル制限
  • (2)クラス制限
  • // Equatable 프로토콜을 채택한 타입만 해당 함수에서 사용 가능 하다는 제약
    
    func findIndex<T: Equatable>(item: T, array:[T]) -> Int? {     // <T: Equatable>
       for (index, value) in array.enumerated() {
           if item == value {
               return index
           }
       }
       return nil
    }
    
    
    let aNumber = 5
    let someArray = [3, 4, 5, 6, 7]
    
    if let index = findIndex(item: aNumber, array: someArray) {
       print("밸류값과 같은 배열의 인덱스: \(index)")
    }
    
    
    // 클래스 제약의 예시
    
    
    class Person {}
    class Student: Person {}
    
    let person = Person()
    let student = Student()
    
    
    
    // 특정 클래스와 상속관계에 내에 있는 클래스만 타입으로 사용할 수 있다는 제약  (구조체, 열거형은 사용 못함)
    // (해당 타입을 상속한 클래스는 가능)
    
    func personClassOnly<T: Person>(array: [T]) {
       // 함수의 내용 정의
    }
    
    
    personClassOnly(array: [person, person])
    personClassOnly(array: [student, student])
    
    //personClassOnly(array: [Person(), Student()])
    逆に、具体化/特定化(専門化)関数を実施することもできる
  • にJENERICを適用した関数を常に実行させると、他の不便は生じませんか?
  • 同じ関数名に特定のタイプを指定すると、その特定のタイプの関数は
  • を実行します.
    // 문자열의 경우, 대소문자를 무시하고 비교하고 싶어서 아래와 같이 구현 가능 ⭐️
    // 위의 findIndex<T: Equatable>(item: T, array:[T]) -> Int? 와 완전 동일
    
    func findIndex(item: String, array:[String]) -> Int? {
       for (index, value) in array.enumerated() {
           if item.caseInsensitiveCompare(value) == .orderedSame {
               return index
           }
       }
       return nil
    }
    
    
    
    let aString = "jobs"
    let someStringArray = ["Jobs", "Musk"]
    
    
    if let index2 = findIndex(item: aString, array: someStringArray) {
       print("문자열의 비교:", index2)
    }

    プロトコルでのJENIC構文の使用

  • プロトコルはどのようにJENIC方式で宣言しますか?
  • 関連タイプとして宣言する必要があります
  • プロトコルは、タイプが採用可能なより高いレベルで
    これは(資格証)要求のみを宣言する概念だからです.
    ジェニーリックタイプとは少し異なる概念(関連タイプ)を追加しただけで、
  • [プロトコル方式]
  • ===> associatedtype T
  • protocol RemoteControl {           // <T>의 방식이 아님
      associatedtype T               // 연관형식은 대문자로 시작해야함(UpperCamelcase)
      func changeChannel(to: T)      // 관습적으로 Element를 많이 사용
      func alert() -> T?
    }
    
    
    
    // 연관형식이 선언된 프로토콜을 채용한 타입은, typealias로 실제 형식을 표시해야함
    
    struct TV: RemoteControl {
      
      typealias T = Int       // 생략 가능
      
      func changeChannel(to: Int) {
          print("TV 채널바꿈: \(to)")
      }
      
      func alert() -> Int? {
          return 1
      }
    
    }
    
    
    
    class Aircon: RemoteControl {
    
      // 연관형식이 추론됨
      
      func changeChannel(to: String) {
          print("Aircon 온도바꿈: \(to)")
      }
    
      func alert() -> String? {
          return "1"
      }
    
    }
    コンストレイントを関連フォーマットに追加すると、
    protocol RemoteControl2 {
      associatedtype Element: Equatable     // <T: Equatable> 제약조건 추가
      func changeChannel(to: Element)
      func alert() -> Element?
    }