Tôi tương đối quen thuộc với Go, đã viết một số chương trình nhỏ trong đó. Rust, tất nhiên, tôi ít quen thuộc hơn nhưng để mắt đến.
Gần đây đã đọc http://yager.io/programming/go.html , tôi nghĩ rằng cá nhân tôi đã kiểm tra hai cách xử lý Generics vì bài viết dường như chỉ trích không công bằng Go khi, trong thực tế, không có nhiều Giao diện không thể hoàn thành một cách thanh lịch. Tôi liên tục nghe thấy sự cường điệu về những đặc điểm của Rust mạnh mẽ như thế nào và không có gì ngoài những lời chỉ trích từ mọi người về Go. Có một số kinh nghiệm trong Go, tôi tự hỏi nó đúng như thế nào và sự khác biệt cuối cùng là gì. Những gì tôi tìm thấy là Đặc điểm và Giao diện khá giống nhau! Cuối cùng, tôi không chắc là mình có thiếu thứ gì không, vì vậy đây là một bản tóm tắt giáo dục nhanh về những điểm tương đồng của chúng để bạn có thể cho tôi biết những gì tôi đã bỏ lỡ!
Bây giờ, hãy xem Giao diện Go từ tài liệu của họ :
Các giao diện trong Go cung cấp một cách để xác định hành vi của một đối tượng: nếu một cái gì đó có thể làm điều này, thì nó có thể được sử dụng ở đây.
Cho đến nay, giao diện phổ biến nhất là Stringer
trả về một chuỗi đại diện cho đối tượng.
type Stringer interface {
String() string
}
Vì vậy, bất kỳ đối tượng đã String()
xác định trên nó là một Stringer
đối tượng. Điều này có thể được sử dụng trong các chữ ký loại sao cho func (s Stringer) print()
gần như tất cả các đối tượng và in chúng.
Chúng tôi cũng có interface{}
bất kỳ đối tượng. Sau đó chúng ta phải xác định loại tại thời gian chạy thông qua sự phản chiếu.
Bây giờ, chúng ta hãy xem Rust Traits từ tài liệu của họ :
Đơn giản nhất, một đặc điểm là một tập hợp các chữ ký phương thức bằng 0 hoặc nhiều hơn. Ví dụ: chúng ta có thể khai báo đặc điểm Printable cho những thứ có thể được in ra bàn điều khiển, với một chữ ký phương thức duy nhất:
trait Printable {
fn print(&self);
}
Điều này ngay lập tức trông khá giống với Giao diện Go của chúng tôi. Sự khác biệt duy nhất tôi thấy là chúng tôi xác định 'Triển khai' các Đặc điểm thay vì chỉ xác định các phương thức. Vì vậy chúng tôi làm
impl Printable for int {
fn print(&self) { println!("{}", *self) }
}
thay vì
fn print(a: int) { ... }
Câu hỏi thưởng: Điều gì xảy ra trong Rust nếu bạn xác định chức năng thực hiện một đặc điểm nhưng bạn không sử dụng impl
? Nó không hoạt động?
Không giống như Giao diện của Go, hệ thống loại của Rust có các tham số loại cho phép bạn thực hiện các khái quát chung và những thứ như interface{}
trong khi trình biên dịch và thời gian chạy thực sự biết loại. Ví dụ,
trait Seq<T> {
fn length(&self) -> uint;
}
hoạt động trên bất kỳ loại nào và trình biên dịch biết rằng loại phần tử Sequence tại thời gian biên dịch thay vì sử dụng sự phản chiếu.
Bây giờ, câu hỏi thực tế: tôi có thiếu bất kỳ sự khác biệt nào ở đây không? Họ có thực sự đó tương tự? Không có một số khác biệt cơ bản hơn mà tôi đang thiếu ở đây? (Trong cách sử dụng. Chi tiết triển khai rất thú vị, nhưng cuối cùng không quan trọng nếu chúng hoạt động giống nhau.)
Bên cạnh sự khác biệt về cú pháp, sự khác biệt thực tế tôi thấy là:
- Go có phương thức gửi tự động so với Rust yêu cầu (?)
impl
Để thực hiện Đặc điểm- Thanh lịch so với rõ ràng
- Rust có các tham số loại cho phép tạo ra các tổng quát thích hợp mà không bị phản xạ.
- Đi thực sự không có phản ứng ở đây. Đây là điều duy nhất mạnh hơn đáng kể và cuối cùng nó chỉ là sự thay thế cho phương pháp sao chép và dán với các chữ ký loại khác nhau.
Đây có phải là sự khác biệt không tầm thường? Nếu vậy, nó sẽ xuất hiện hệ thống Giao diện / Loại của Go, trên thực tế, không yếu như nhận thức.
AnyMap
là một minh chứng tốt cho những điểm mạnh của Rust, kết hợp các đối tượng đặc điểm với khái quát để cung cấp một sự trừu tượng hóa an toàn và biểu cảm của điều mong manh mà trong Go sẽ cần phải được viếtmap[string]interface{}
.