Pull to refresh

Comments 12

Меня в Go больше всего смущает отношение разработчиков, что они не смогли (или не захотели) добавлять функциональность по типу filter, map и прочее, а разработчик с habr смог.

Ну автор не первый это придумал, это общее место, скорее. Ну и map через точку получается кривой, каррирования нет, монады тяжеловесные. Го всё же не функциональный язык даже с генериками. Но писать на нём можно достаточно быстро, в чужом коде разбираться тоже, когнитивная нагрузка невысокая. У меня и на отладку существенно меньше времени уходит, чем с плюсами или жаваскриптом.

Не знаю есть ли смысл разводить холивар, уже не раз писал на эту тему.
По поводу когнитивной нагрузки, если сравнивать с тем же Kotlin то в Kotlin гораздо проще понять что делает метод ввиду того что если на Go не использовать самописные map, filter, any, all то приходится гораздо больше времени тратить чтобы понять что тот или иной for делает


По поводу отладки вообще другой разговор, когда во всех нормальных языках есть конструктор и я могу поставить точку остановки на вызов конструктора и найти где тот или иной объект был создан за один раз, то в Go это превращается в целое приключение если создание объекта есть в нескольких местах, а учитывая передачу по значению то вариации откуда пошел не тот объект становится еще больше

Или же я могу без проблем сделать getter setter в том же жаваскрипте, и опять же поставить точку остановки на установку значения, в Go опять я этого сделать не могу, если значения устанавливаются напрямую в объект.

С выполнением кода тоже есть вопросы, в отладке в Goland (когда я работал с Go) как то не очень работали функции которые возвращали несколько значений, и нельзя было на точке остановки постоять и выполнять код для проверки каких-либо данных

За плюсы ничего не говорю, сравниваю с JavaScript и Kotlin/Java/С#

Для конструктора используется паттерн

type MyType struct {}

fun NewMyType() *MyType {
  return &MyType{}
}

package main

import "fmt"

type MyType struct {
	value string
}

func NewMyType() *MyType {
	println("create")
	return &MyType{}
}

func main() {
	myType := MyType{
		value: "F*ck constructor",
	}
	fmt.Println(myType.value)
}

Твой пример работает только если во всем проекты вызывается через этот синтетический конструктор, но если в каком либо проекте программисты почему-то решили так как не делать, то этот NewMyType чуть больше чем бесполезен

Да, Go это про конвенции которые надо выработать в своих проектах.

Мы в итоге пришли к следующей формуле - если важно, чтобы твою структуру делали только через конструктор - делай ее приватной

type _MyType struct {} // в терминах Kotlin - это internal
func NewMyType() *_MyType {...} // а это public

Если так делать - то варианта прямого создания абы как _MyType не остается.

Вторая конвенция это конечно отношение к "пакету" в Go примерно как к "классу" в Java/Kotlin, а не как к пакету в Java/Kotlin. При таком понимании - пакет это синглтон со статическими методами (функциями), с inner class (структуры и их методы). То есть пакет в Go это не "коллекция связанного кода", как в Java, а "компонент под ключ", что ближе к "большому классу". В принципе большинство пакетов в Go у самих Google примерно так и выдержаны. Это понимание тоже позволяет лучше спланировать API и определиться с видимостью тех или иных структур и функций

https://github.com/robpike/filter

Ну вроде как есть такое поделие от Роба Пайка, но как он там заметил можно просто for использовать смысла столько же :)

Ну я думаю у них на это был серьезный мотив именно связанный с тем, что генерики у них пока не очень. Без наличия стандартного механизма обобщения не стоит замахиваться на "стандартный LINQ для Go" и в целом взять готовый с инета или сделать свой для своих нужд не сложно. К тому же в случае го это тем более бессмысленно так как нет обобщенного понятия Iterable или аналога. Плюс это не будет полноценным если сразу не решить с унификацией []int и <-chan int

А это точно не тривиал бы был

Свои 5 копеек как автор вставлю. Kotlin богаче как язык. Но как и из статьи видно - голанг также вполне комфортный. Если говорить про сам язык, то менять Котлин на го смысла нет. Но дефект котлина не в нём самом, а в том что JVM, которая не радует когда много подов всяких сервисов. Я честно ждал джва года, что kotlin native будет выпущен в релиз... Но к сожалению он не известно когда будет доведён до ума и если нужен Натив, то выбор очень быстро падает на go. C/C++ вообще даже не рассматривали. На расте я пописываю, но в командный общий стек не стал вносить, тяжеловат в освоении.

Фагим, меня больше озадачила постановка: переписать код с Kotlin на Go.

Это два языка, которые практически не пересекаются по назначению. Go - это низкоуровневый язык с высокой производительностью и скорее для системных задач; Kotlin - высокоуровневый язык с высокой скоростью разработки и скорее для бизнесовых задач. Композировать их, добавляя в критические места программы на Котлин вставки на Go с использованием интероперабельности с C - это нормальная идея. Но перенос один-в-один задач СпектрумДата на Котлин в Go у меня вызывает непонимание.

Можно ли раскрыть примеры таких задач?

И я ни в коей мере не соглашусь с Вашей исходной посылкой - производительности у Go не сильно больше чем у Java по крайней мере на gRPC (посмотрите официальные бенчмарки), низкоуровневости в нем тоже не сказать, что много. И я не слышал чтобы Go использовался для системных задач (для таких задач наличие рантайма с GC не очень характерно). Они с Kotlin одного поля ягоды. Разница существенная не в низком уровне или системности, а в поддержке нативной компиляции. В случае с Kotlin это Kotlin Native - но этот продукт не зрелый, поэтому используем Go.

Отвечая на ваш вопрос про портирование.

Переписывания того что уже есть с языка на язык задачи действительно не было (у нас в команде), хотя другая команда именно переписывала на Go, с PHP.

Но часть новых сервисов было решено делать на Go, а не на Java (по причине огромного футпринта в памяти JVM), хотя уже много было наработок на Kotlin (и хотелось их максимально использовать и дальше). И при этом требуется поддержание некоторого SDK на 2-х языках (для других команд) - там всякие внешние коннекторы и спеки и всякие кастомные маршаллизаторы - это на 2-х языках ведется. Соответственно была задача максимально быстро перенести часть шаблонных наработок чтобы они были и в GO и во-вторых есть код который реально сразу в 2 языка сопровождается.

А вот то, что вы описчываете "быстро", "низкоуровнево" и системно - это скорее про Rust если из современных платформ смотреть и с C/C++ не связываться. Вот они как раз на другой поляне играют несколько. Rust тоже есть в стеке (но это скорее просто чтобы какие-то квалификации такого рода в коллективе были и не ржавели), переводить всех на Rust - это действительно тяжело и в итоге себя не оправдывает. Но где он уместен - тоже применяем. Вот там я не скажу что получается один в один переносить, не получается - другого планирования требует язык.



А

По поводу интеропа с C смотрели и Kotlin Native и Go и Rust - лучше всего как ни странно получается когда приложение на C, а в него увязывается например Kotlin Native или Rust и в нем используется Kotlin Native. Go с Kotlin не очень дружат - основная причина, что Kotlin формирует *.h где все сделано через (void*) (объекты воспроизводятся с методами) - ни при импорте в C ни при импорте в Rust проблемы нет, а вот Golang как оказалось его CGO это не поддерживает - приходится кроме штатного хидера еще пилить какие-то костыли с подменой имен и реекспортом.
По обратному интеропу та же примерно история - 2 разных GC не шибко хотят дружить - то есть как-то все это импортится, но какой-то уверенности, что все что надо в нужный момент вычищается нет. При импорте из C или Rust такого вопроса не встает особо. В общем как раз Go/Kotlin interop не сказать что очень уж взлетает

Sign up to leave a comment.

Articles