Из Go в Rust или Ад шаблонов

9261d871cdc336d9330927b4dbf2d8f5.png

В Go ввели шаблоны и он потерял одно из своих основных преимуществ: легкую читаемость.

Накидал простой пример:

package main
import "fmt"

type MyObj[T int] struct{ a T }
type MyObj2[T MyObj[E], E int] struct{ b T }
type MyObj3[T MyObj2[A, E], A MyObj[E], E int] struct{ с T }
type MyObj4[T MyObj3[B, A, E], B MyObj2[A, E], A MyObj[E], E int] struct{ d T }

func main() {
	my := MyObj[int]{a: 10}
	my2 := MyObj2[MyObj[int], int]{b: my}
	my3 := MyObj3[MyObj2[MyObj[int], int], MyObj[int], int]{с: my2}
	my4 := MyObj4[MyObj3[MyObj2[MyObj[int], int], MyObj[int], int], MyObj2[MyObj[int], int], MyObj[int], int]{d: my3}

	fmt.Println("Data: ", my, my2, my3, my4)
}

А в реальных проектах с кучей библиотек будут огромные строки указания параметров шаблона. Ни о какой легкой читаемости больше речь не идет, а ведь здесь мы всего лишь хотим сказать, что MyObj4.d содержит значение типа MyObj3.

Как же обходились без шаблонов в Go 13 лет? Это не помешало выпустить отличные библиотеки и сделать хорошую стандартную библиотеку! При этом сохранялась лаконичность и легкость языка. А теперь…

У Rust и Go много общего: отсутствие классов, интерфейсы/трейты, принцип обработки ошибок и т.п. Если не брать во внимание GC, то кажется, что Rust — это улучшенная версия Go. Rust дает намного больше возможностей и гибкости, но берет «плату» в виде «владения» и «времени жизни» о которых нужно думать. На Rust можно так же начать писать в стиле Go, но все портят библиотеки. У Go, как мне кажется, отличные основные библиотеки (Gin, Fiber, GORM и т.п.) с отличной документацией из которой сразу понятно как использовать + за счет легкой читаемости языка можно быстро глянуть в IDE исходники нужной функции. А еще стандартная библиотека которая покрывает практически любые потребности. Интерфейс у всех фреймворков очень похож и можно быстро поменять одну библиотеку на другую.

В Rust не так. Тут принцип, что есть очень маленькая stdlib, а все дополнительные возможности должны писаться сообществом, поэтому появляются фреймворки типа Tokio. Минус такого подхода в том, что нет единого стандарта (как в Go) и каждый лепит API на свое усмотрение (получается этакий Python). Документация хуже чем у Go, часто просто сигнатуры методов и пара примеров, без описания, что и как. А еще макросы. Это все добавляет много сложности на начальном этапе выбора стека, но когда разберетесь с фреймворками и библиотеками, писать становится быстрее и меньше чем на Go. (хотя бы за счет другой обработки ошибок, из-за чего я и начал смотреть на Rust вместо Go)

Так вот про шаблоны. Понадобилось мне в Rust использовать ORM так, то бы при запуске на локальном ПК использовался sqlite, а на сервере postgre. И это оказалось проблемой в библиотеках Rust. Что бы сделать например обобщённую функцию для sqlx нужно описать портянку из параметров шаблонов, притом это не очевидно и нужно долго выискивать, что где прописать. Но ведь в Go например есть GORM, который без всяких шаблонов делает это. Получается, что шаблоны усложняю код, но при этом они не нужны для реализации функционала.

Вот пример типа из Rust (с первого раза же понятно, что это за тип? сарказм):

SelectStatement, 
diesel::query_builder::select_clause::SelectClause>, 
diesel::query_builder::distinct_clause::NoDistinctClause, 
diesel::query_builder::where_clause::WhereClause>>, diesel::query_builder::order_clause::NoOrderClause, 
LimitOffsetClause>, 
NoOffsetClause>>

И это то, во что превратится Go с шаблонами…

Раз теперь код в Go будет выглядеть как в Rust, то зачем продолжать использовать Go?
Получается только из-за работодателей, т.к. на рынке требуется много Go программистов и не требуются Rust.?

А что вы думаете по поводу generics (шаблонов). Благо это или зло для разработки?

Примечание: я не являюсь экспертом в Go и Rust и поэтому могу ошибаться в каких то моментах

© Habrahabr.ru