Đối với người mới bắt đầu, chúng ta hãy giải thích các lỗi:
Given:
class Foo<T:Hashable> { }
class SubFoo<String> : Foo<String> { }
Phần khó hiểu ở đây là chúng tôi mong đợi "String" có nghĩa là cấu trúc định nghĩa Swift nắm giữ một bộ sưu tập của các nhân vật. Nhưng không phải vậy.
Ở đây, "Chuỗi" là tên của loại chung mà chúng tôi đã cung cấp cho lớp con mới, SubFoo
. Điều này trở nên rất rõ ràng nếu chúng tôi thực hiện một số thay đổi:
class SubFoo<String> : Foo<T> { }
Đường này tạo lỗi cho T
khi sử dụng loại không khai báo.
Sau đó, nếu chúng ta thay đổi dòng này:
class SubFoo<T> : Foo<T> { }
Chúng tôi đang trở lại với lỗi tương tự bạn ban đầu đã có, 'T' không phù hợp với 'Hashable'. Điều này hiển nhiên ở đây, vì T không gây nhầm lẫn tên của một kiểu Swift hiện có xảy ra để phù hợp với 'Hashable'. Rõ ràng 'T' là một chung chung.
Khi chúng tôi viết 'Chuỗi', nó cũng chỉ là tên trình giữ chỗ cho loại chung, và không thực sự là loại String
tồn tại trong Swift.
Nếu chúng ta muốn có một tên khác nhau cho một loại hình cụ thể của một lớp chung, cách tiếp cận thích hợp là gần như chắc chắn một typealias
:
class Foo<T:Hashable> {
}
typealias StringFoo = Foo<String>
này là hoàn toàn hợp lệ Swift, và nó biên dịch tốt.
Nếu thay vào đó những gì chúng tôi muốn thực sự là phân lớp và thêm phương thức hoặc thuộc tính vào lớp chung, thì chúng tôi cần cụ thể hơn cho những gì chúng tôi cần.
Trở lại với vấn đề ban đầu, chúng ta hãy đầu tiên thoát khỏi các lỗi:
class Foo<T: Hashable>
class SubFoo<T: Hashable> : Foo<T> { }
này là hoàn toàn hợp lệ Swift. Nhưng nó có thể không đặc biệt hữu ích cho những gì chúng tôi đang làm.
Lý do duy nhất chúng ta không thể làm như sau:
class SubFoo<T: String> : Foo<T> { }
chỉ đơn giản là vì String
không phải là một lớp Swift - đó là một cấu trúc. Và điều này không được phép cho bất kỳ cấu trúc nào.
Nếu chúng ta viết một giao thức mới được thừa kế từ Hashable
, chúng tôi có thể sử dụng:
protocol MyProtocol : Hashable { }
class Foo<T: Hashable> { }
class SubFoo<T: MyProtocol> : Foo<T> { }
này là hoàn toàn hợp lệ.
Ngoài ra, lưu ý rằng chúng tôi không thực sự phải kế thừa từ Hashable
:
protocol MyProtocol { }
class Foo<T: Hashable> { }
class SubFoo<T: Hashable, MyProtocol> { }
Đây cũng là hoàn toàn hợp lệ.
Tuy nhiên, lưu ý rằng, vì lý do gì đó, Swift sẽ không cho phép bạn sử dụng lớp học ở đây. Ví dụ:
class MyClass : Hashable { }
class Foo<T: Hashable> { }
class SubFoo<T: MyClass> : Foo<T> { }
Swift bí ẩn phàn nàn rằng 'T' không phù hợp với 'Hashable' (ngay cả khi chúng ta thêm đoạn mã cần thiết để làm cho nó để
Cuối cùng, bên phải. phương pháp tiếp cận và cách tiếp cận phù hợp nhất với Swift sẽ là viết một giao thức mới kế thừa từ 'Hashable' và thêm bất kỳ chức năng nào vào nó mà bạn cần. Điều quan trọng là wha tever lớp con của chúng tôi có, nó có các phương pháp cần thiết và tài sản mà chúng tôi cần cho bất cứ điều gì chúng tôi đang làm.
Không phải vậy. Có vấn đề/giới hạn Swift liên quan đến vấn đề này, xem http://stackoverflow.com/questions/24138359/limitation-with-classes-derived-from-generic-classes-in-swift – Ixx
@lxx: Ick. Tôi nghi ngờ đó vẫn là nguyên nhân *, nhưng bạn muốn có một giải pháp khác. Tôi đã chỉnh sửa câu trả lời của mình bằng một giải pháp khả thi để thử. –
Vâng, vâng, giải pháp với thông số loại bỏ đi hoạt động nhưng tôi đã không thử nó bởi vì nó xấu xí. Ở phía bên kia, tôi đã thử lại giải pháp typealias và nó hoạt động ngay bây giờ. Có một vấn đề bởi vì (câu trả lời được chọn) nó sử dụng Int làm trình giữ chỗ, đó là lý do tại sao tôi đã thử sử dụng String, tham số và nó đã gây ra lỗi. Tôi đã thay thế bằng T và tuyên bố typealias dưới lớp, không phải nó biên dịch. Nó vẫn là một cách giải quyết mặc dù. Cảm ơn anyways đã chỉ cho tôi trở lại giải pháp chính xác :) – Ixx