Я відносно знайомий з 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 має автоматичну розсилку методів проти Руста, яка вимагає (?)
implS для реалізації ознаки- Елегантний проти явного
- У іржі є параметри типу, які дозволяють отримувати належні генеричні дані без відображення.
- Тут дійсно немає відповіді. Це єдине, що значно потужніше, і це, в кінцевому рахунку, лише заміна методів копіювання та вставлення з різними типами підписів.
Це єдині нетривіальні відмінності? Якщо так, то, здається, система інтерфейсу / типу Go на практиці не така слабка, як сприймається.
AnyMap- це хороша демонстрація сильних сторін Іржі, поєднання об'єктів риси з загальними, щоб забезпечити безпечну та виразну абстракцію тендітної речі, про яку в «Го» потрібно було б написатиmap[string]interface{}.