2015-06-23 43 views
9

Tôi đã trải qua các hướng dẫn Swift trên trang web của nhà phát triển Apple, nhưng tôi không hiểu các khái niệm về Generics. Có ai có thể giải thích nó một cách đơn giản không? Ví dụ:Generics in Swift 2.0

func swapTwoValues<T>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 
+0

Câu hỏi hay, bạn nên cân nhắc chọn câu trả lời cho câu hỏi này nếu một câu trả lời cho câu hỏi của bạn! Điều này cải thiện chất lượng bài đăng của bạn và do đó mang lại lợi ích cho cộng đồng. –

Trả lời

11

Nếu không sử dụng Generics trong ví dụ bạn đưa ra, bạn sẽ phải quá tải swapTwoValues cho tất cả các loại bạn muốn trao đổi. Ví dụ:

func swapTwoValues(inout a: Int, inout b: Int) { 
    let temp = a 
    a = b 
    b = temp 
} 

func swapTwoValues(inout a: String, inout b: String) { 
    let temp = a 
    a = b 
    b = temp 
} 

// Many more swapTwoValues functions... 

Điều duy nhất khác biệt giữa các chức năng ở trên là loại chúng chấp nhận; mã bên trong mỗi mã đều giống nhau. Do đó, tốt hơn nên viết một chức năng chung có thể thực hiện bất kỳ loại nào.

Điều quan trọng cần lưu ý là bạn không thể thay thế T bằng Any. Sẽ không có bảo đảm ab sẽ là cùng loại - bạn không thể hoán đổi một số IntString chẳng hạn.

1

Về cơ bản, điều đó có nghĩa là nó không phải là loại cụ thể. Bạn sử dụng T và chỉ cần viết một chức năng thay vì viết nhiều chức năng cho từng loại Int, Double, Float, String, vv

4

Trong ví dụ T của bạn thể hiện Loại. Và một khi thiết lập kiểu đó phù hợp với toàn bộ hàm.

func swapTwoValues<T>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 

Nếu T là Int trong trường hợp tham số a thì đó cũng phải là Int trong trường hợp tham số b. Như thể hiện trong việc sử dụng này của hàm:

var valueA = 2 
var valueB = 4 
swapTwoValues(&valueA, b: &valueB) 

valueA // 4 
valueB // 2 

Chúng tôi không thể trao đổi một String cho một Int ví dụ hoặc thậm chí là một Int cho một đôi, nhưng miễn là loại đều giống nhau thì phương pháp chung này sẽ mất bất kỳ Loại, bởi vì nó là không kiềm chế trong tất cả các khía cạnh khác.

var valueA = "Hello" 
var valueB = "Swift" 
swapTwoValues(&valueA, b: &valueB) 

valueA // "Swift" 
valueB // "Hello" 

Điều này không có nghĩa là nhiều loại được loại trừ khỏi các chức năng chung. Bạn chỉ cần gán một ký tự khác để đại diện cho các loại khác nhau (chữ được sử dụng không liên quan, T được sử dụng đơn giản vì nó là chữ cái đầu tiên của Type nhưng không có lý do gì mà nó không thể thay thế bằng Q, ví dụ, hoặc bất kỳ thư khác):

func swapTwoValues<T,S>(inout a: T, inout b: T, inout c: S, inout d: S) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 

    let temporaryC = c 
    c = d 
    d = temporaryC 
} 

var valueA = 2 
var valueB = 4 

var valueC = "Hello" 
var valueD = "Swift" 
swapTwoValues(&valueA, b: &valueB, c:&valueC, d:&valueD) 

valueA // 4 
valueB // 2 

valueC // "Swift" 
valueD // "Hello" 

Lưu ý: chúng tôi vẫn không thể trao đổi chữ T cho chữ S vì Swift là ngôn ngữ được nhập mạnh và chúng tôi không đảm bảo chúng giống nhau.

Nó trở nên thú vị hơn khi các giao thức có liên quan đến hạn chế các loại chung. Ở đây tôi làm như vậy với các UnsignedIntegerType:

func swapTwoValues<T: UnsignedIntegerType>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 

var valueA:UInt = 10 
var valueB:UInt = 11 

swapTwoValues(&valueA, b: &valueB) 

loại Bây giờ chỉ như uint, uint8, UInt32, vv đều được chấp nhận và tất cả các giá trị khác sẽ bị từ chối và tạo ra một lỗi.

Lưu ý: Lý do ràng buộc các loại sử dụng giao thức là để các phương pháp nhất định có thể được đảm bảo hoạt động. Ví dụ, nếu một hàm generic được yêu cầu để tạo một thể hiện kiểu mới, thì nó phải chấp nhận một giao thức với một phương thức init. (Bạn có thể kiểm tra việc chấp nhận giao thức cho từng loại trong tài liệu của Apple.)

Chúng ta có thể đi xa hơn và sử dụng từ khóa where để xác định các loại chứa trong một bộ sưu tập chung:

func swapTwoValues<T: CollectionType where T.Generator.Element: UnsignedIntegerType>(inout a: T, inout b: T) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 
} 

var valueA:[UInt] = [10,12,4] 
var valueB:[UInt] = [11,45,67] 

swapTwoValues(&valueA, b: &valueB) 

valueA // [11, 45, 67] 
valueB // [10, 12, 4] 

Hoặc làm những việc như kiểm tra rằng một loại thứ hai là tương đương với các loại yếu tố trong một bộ sưu tập sử dụng ==:

func swapTwoValues<T: CollectionType, S where S == T.Generator.Element>(inout a: T, inout b: T, inout c: S, inout d: S) { 
    let temporaryA = a 
    a = b 
    b = temporaryA 

    let temporaryC = c 
    c = d 
    d = temporaryC 
} 

đọc thêm: Mọi thứ trở nên thú vị hơn với protocol extensions in Swift 2 vì bây giờ chức năng chung có thể đảm nhận các đặc điểm của phương pháp Type, mà làm cho họ xa m quặng có thể phát hiện được.