Saya relatif akrab dengan Go, setelah menulis sejumlah program kecil di dalamnya. Karat, tentu saja, saya kurang terbiasa tetapi mengawasi.
Setelah baru-baru ini membaca http://yager.io/programming/go.html , saya pikir saya akan secara pribadi memeriksa dua cara Generics ditangani karena artikel tersebut kelihatannya secara tidak adil mengkritik Go ketika, dalam praktiknya, tidak ada banyak antarmuka. tidak bisa menyelesaikan dengan elegan. Saya terus mendengar hype tentang betapa kuatnya Karakter Rust dan tidak ada apa-apa selain kritik dari orang-orang tentang Go. Setelah memiliki pengalaman dalam Go, saya bertanya-tanya seberapa benar itu dan apa perbedaan akhirnya. Apa yang saya temukan adalah bahwa Ciri dan Antarmuka sangat mirip! Pada akhirnya, saya tidak yakin apakah saya melewatkan sesuatu, jadi di sini adalah ikhtisar pendidikan singkat tentang kesamaan mereka sehingga Anda dapat memberi tahu saya apa yang saya lewatkan!
Sekarang, mari kita lihat Go Interfaces dari dokumentasinya :
Antarmuka di Go menyediakan cara untuk menentukan perilaku objek: jika sesuatu dapat melakukan ini, maka itu dapat digunakan di sini.
Sejauh ini antarmuka Stringer
yang paling umum adalah yang mengembalikan string yang mewakili objek.
type Stringer interface {
String() string
}
Jadi, objek apa pun yang telah String()
didefinisikan di atasnya adalah Stringer
objek. Ini dapat digunakan dalam jenis tanda tangan sehingga func (s Stringer) print()
mengambil hampir semua objek dan mencetaknya.
Kami juga memiliki interface{}
yang mengambil objek apa pun. Kami kemudian harus menentukan jenis saat runtime melalui refleksi.
Sekarang, mari kita lihat Karat Karakter dari dokumentasi mereka :
Paling sederhana, suatu sifat adalah seperangkat tanda tangan metode nol atau lebih. Sebagai contoh, kita dapat mendeklarasikan sifat Printable untuk hal-hal yang dapat dicetak ke konsol, dengan tanda tangan metode tunggal:
trait Printable {
fn print(&self);
}
Ini segera terlihat sangat mirip dengan Antarmuka Go kami. Satu-satunya perbedaan yang saya lihat adalah kita mendefinisikan 'Implementasi' Traits daripada hanya mendefinisikan metode. Jadi kita lakukan
impl Printable for int {
fn print(&self) { println!("{}", *self) }
}
dari pada
fn print(a: int) { ... }
Pertanyaan Bonus: Apa yang terjadi di Rust jika Anda mendefinisikan fungsi yang mengimplementasikan suatu sifat tetapi Anda tidak menggunakannya impl
? Itu tidak berhasil?
Tidak seperti Go's Interfaces, sistem tipe Rust memiliki parameter tipe yang memungkinkan Anda melakukan generik yang tepat dan hal-hal seperti interface{}
ketika kompiler dan runtime benar-benar mengetahui jenisnya. Sebagai contoh,
trait Seq<T> {
fn length(&self) -> uint;
}
bekerja pada semua jenis dan kompiler tahu bahwa jenis elemen Sequence pada waktu kompilasi daripada menggunakan refleksi.
Sekarang, pertanyaan aktual: apakah saya kehilangan perbedaan di sini? Apakah mereka benar-benar yang serupa? Apakah tidak ada perbedaan mendasar yang saya lewatkan di sini? (Dalam penggunaan. Detail implementasi menarik, tetapi pada akhirnya tidak penting jika fungsinya sama.)
Selain perbedaan sintaksis, perbedaan aktual yang saya lihat adalah:
- Go memiliki pengiriman metode otomatis vs. Rust yang memerlukan (?)
impl
S untuk mengimplementasikan Trait- Elegan vs. Eksplisit
- Karat memiliki parameter tipe yang memungkinkan generik yang tepat tanpa refleksi.
- Go benar-benar tidak memiliki respons di sini. Ini adalah satu-satunya hal yang secara signifikan lebih kuat dan pada akhirnya hanya penggantian untuk metode menyalin dan menempel dengan tanda tangan jenis yang berbeda.
Apakah ini satu-satunya perbedaan yang tidak sepele? Jika demikian, akan muncul sistem Go's Interface / Type, dalam praktiknya, tidak selemah yang dirasakan.
AnyMap
adalah demonstrasi yang baik dari kekuatan Rust, menggabungkan objek-objek sifat dengan obat-obatan generik untuk memberikan abstraksi yang aman dan ekspresif dari hal rapuh yang harus ditulis oleh Gomap[string]interface{}
.