Я відносно знайомий з Go, написавши в ньому ряд невеликих програм. Іржу, звичайно, я менш знайомий, але слідкую за цим.
Нещодавно прочитавши http://yager.io/programming/go.html , я подумав, що я особисто вивчу два способи роботи з дженеріками, оскільки стаття, здавалося, несправедливо критикує Іде, коли на практиці інтерфейсів було не так багато не вдалося виконати елегантно. Я продовжував чути галас про те, наскільки потужні риси Руста, і нічого, окрім критики з боку людей щодо Go. Маючи певний досвід роботи в Go, я замислився, наскільки це правда і якими були в кінцевому рахунку відмінності. Що я виявив, що риси та інтерфейси досить схожі! Зрештою, я не впевнений, чи щось мені не вистачає, тож ось короткий навчальний цикл їх подібності, щоб ви могли сказати мені, що я пропустив!
Тепер давайте розглянемо Go Interfaces з їх документації :
Інтерфейси в Go надають спосіб уточнити поведінку об'єкта: якщо щось може це зробити, то це можна використовувати тут.
На сьогодні найпоширеніший інтерфейс, Stringer
який повертає рядок, що представляє об'єкт.
type Stringer interface {
String() string
}
Отже, будь-який об’єкт, який String()
визначив на ньому, є Stringer
об'єктом. Це може бути використано в таких підписах, що func (s Stringer) print()
приймають майже всі об'єкти та друкують їх.
У нас також є interface{}
який приймає будь-який об’єкт. Потім ми повинні визначити тип під час виконання за допомогою відображення.
Тепер давайте розглянемо риси іржі з їх документації :
Найпростіше, ознака - це набір нульових або більше підписів методів. Наприклад, ми можемо оголосити ознаку Printable для речей, які можна надрукувати на консолі, з єдиним підписом методу:
trait Printable {
fn print(&self);
}
Це відразу схоже на наші Go Interfaces. Єдина відмінність, яку я бачу, полягає в тому, що ми визначаємо «Реалізацію» рис, а не просто визначаємо методи. Отже, ми
impl Printable for int {
fn print(&self) { println!("{}", *self) }
}
замість
fn print(a: int) { ... }
Питання про бонус: Що станеться в Rust, якщо ви визначите функцію, яка реалізує ознаку, але ви не використовуєте impl
? Це просто не працює?
На відміну від інтерфейсів Go, система типу Руста має параметри типу, які дозволяють робити належні загальні відомості та такі речі, як interface{}
компілятор та час виконання фактично знають тип. Наприклад,
trait Seq<T> {
fn length(&self) -> uint;
}
працює над будь-яким типом, і компілятор знає, що тип елементів послідовності під час компіляції, а не використання відображення.
Тепер, власне питання: я пропускаю тут якісь відмінності? Чи справді вони такі схожі? Чи не є якась більш принципова різниця, яку мені тут не вистачає? (У використанні. Деталі впровадження цікаві, але в кінцевому рахунку не важливі, якщо вони функціонують однаково.)
Крім синтаксичних відмінностей, я бачу фактичні відмінності:
- Go має автоматичну розсилку методів проти Руста, яка вимагає (?)
impl
S для реалізації ознаки- Елегантний проти явного
- У іржі є параметри типу, які дозволяють отримувати належні генеричні дані без відображення.
- Тут дійсно немає відповіді. Це єдине, що значно потужніше, і це, в кінцевому рахунку, лише заміна методів копіювання та вставлення з різними типами підписів.
Це єдині нетривіальні відмінності? Якщо так, то, здається, система інтерфейсу / типу Go на практиці не така слабка, як сприймається.
AnyMap
- це хороша демонстрація сильних сторін Іржі, поєднання об'єктів риси з загальними, щоб забезпечити безпечну та виразну абстракцію тендітної речі, про яку в «Го» потрібно було б написатиmap[string]interface{}
.