Перейти на простой язык

задняя часть Go программист C++

Из любопытства я недавно вступил в контакт с некоторыми из кода GO. У меня есть некоторое понимание этого раньше, но никогда не пыталась писать (не требовать). Но теперь мы решили использовать команду Go для разработки проекта, поэтому я думаю, что это хорошая возможность получить практический опыт.

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

Сообщество на самом деле не такое уж приятное, особенно те, кто выступает за Go из-за его простоты. Кажется, простота стала модным словом в сообществе Go, и многие люди повторяли его снова и снова, не задумываясь.

Мне это кажется неудачным, поскольку Go, на мой взгляд, «чрезвычайно простой язык»:

  1. Не должно быть основной причиной использования Go.
  2. Найдите другие более благоприятные причины для направления от их проблем
  3. Даже не правда (не совсем просто)

В этом посте я хочу проанализировать некоторые простые моменты, связанные с Go.

Прежде чем идти дальше, я хотел бы подчеркнуть одну вещь.: Этот пост — не критика Go, а способ продвижения и защиты Go. Иногда я могу критиковать какой-то аспект языка, но это не наша цель, я просто попытаюсь рассказать об этом в неформальной, основанной на фактах манере, которая присутствует в каждом языке.

откуда я

Для работы и хобби использую несколько языков программирования одновременно. Я не сторонник концепции «любимого языка». В прошлом у меня было несколько любимых языков, но осознание часто является мимолетной эмоцией, которая меняется со временем.

В своей работе я используюC++иPythonНапишите большой серверный код сервисов. В прошлом я работал над одной операционной системой, которую вы, возможно, знаете, и занимался встроенной работой. В любительском проекте я занимался другими вещами.

Я не хвастаюсь (я не эксперт), я просто хочу показать, что у меня есть хотя бы некоторые идеи во многих областях программирования, и я всегда старался быть непредвзятым.

Итак, не волнуйтесь, давайте приступим к делу и рассмотрим несколько моментов.

1. «В Go очень мало ключевых слов по сравнению с основными языками».

Начну с одного из самых распространенных примеров. Это будет мантрой при продвижении Go.

Во-первых, даже если бы это было правдой, я не знаю, почему количество ключевых слов может быть таким важным фактором при оценке кривой обучения или сложности языка. Конечно, это может быть проблемой, если ключевых слов тысячи. Но большинство языков имеют не более нескольких десятков ключевых слов, и при таком масштабе количество ключевых слов не имеет значения.

Я не слышал, чтобы кто-то жаловался на язык из-за количества ключевых слов.

Во-вторых, поезжание «мало» ключевое слово - это на самом деле не более того, чем уютный хитрость адвоката (может быть, я даже не думаю, что это ложная реклама).Идти спецификацияПеречислено 25 ключевых слов, что действительно меньше, чем в большинстве языков. Но мне кажется, что в Go представлено не меньше понятий, чем в других ключевых словах языка, в Go нет этих ключевых слов, но соответствующие понятия по-прежнему являются частью языка (т.е. фактическая сложность остается прежней).

Чтобы проиллюстрировать, что я имею в виду, рассмотримwhileцикл. В Go нет этого ключевого слова, это правда, но в нем все еще есть цикл while,ДокументацияТем не менее, его цель — просто повторно использовать другие ключевые слова.

Другим таким примером являетсяprivateиpublic. В Go нет этих ключевых слов, но естьprivateиpublic, он просто использует регистр букв вместо ключевых слов.

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

2. Параметры приемника

Параметр приемникаКак-то странно для меня. Похоже, Go не рекомендует использоватьthisиself, но метод по-прежнему требуется, поэтому есть «параметры получателя», которые в основном одинаковы, за исключением того, что сигнатура метода выглядит странно.

Есть проблема с параметром приемника, при доступе к методу мне нужно знать имя параметра приемника (произвольное), чтобы было понятно, что делает метод. Подсветка синтаксиса становится проблемой из-за отсутствия ключевых слов. (Видите? Вот пример того, как сокращение ключевых слов на самом деле усложняет задачу.) Это вроде какC++Скрытыйthis.

Вот новичка легко запутатьпример.

ИМХО самый простой и прямой способ выразить сток этоUFCS, а не C++ или Go. Но, как я уже сказал, я не жалуюсь на Go, я действительно не возражаю против точки зрения берущего аргумента (если я не выношу странностей C++, я могу жить с Go).

3. Возвращаемое значение функции

Если полученных параметров недостаточно, функция может быть объявлена ​​различными формами возвращаемых значений. Обычно язык позволяет пройтиreturn语句返回函数中的一个值。而在 Go 语言中,你可以返回多个值(我认为可以用更优雅的方式通过元组来解决,但是就这样吧)。 Кроме тогоименованное возвращаемое значение. На мой взгляд, это не очень хорошая идея, так как это позволяет нам писать головокружительный код в местах, где трудно найти возвращаемое значение. В сочетании с параметром приемника вы можете создать сигнатуру функции следующим образом:

func (f Foobar) Something(a int, b int, c int) (foo int, bar int) {
    // ...
}

Это действительный код Go. Как видите, есть три параметра. Я действительно не хочу, чтобы кто-то пытался выбрать этот «простой», потому что этот синтаксис не что иное, как простой.

4. «Нет наследства»

Go (возможно, только община), похоже, очень против «традиционной ООП» (независимо от того, какой из них, может быть, Java или C ++), я помню, что есть хорошая вещь, чтобы сказать, что Go не наследует это хорошая вещь Отказ

Кроме того, в Go есть функция, называемаявстроенный, эта документация и некоторые сообщения в блогах утверждают, что в Go нет наследования. Я пытался использовать его по-разному, и я не думаю, что Go против наследования. В документации, указанной выше, говорится:

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

Есть ли разница? Наследование обычно работает таким же образом, и унаследованные методы также работают с внутренними типами.

Мне кажется, единственное, что действительно отличается от Go, это то, что полиморфизм отделен от структур. Вам нужно использовать интерфейсы для использования полиморфизма. Но как только вы это сделаете, делайте вещи, очень похожие на традиционный ООП, включая переопределение методов  - .вот демо.

О ходите, одна вещь, которую я удивлен - эта дверь так называемый простой язык - вы даже можете добиться нескольких наследний.Действительно плохо. список рассылки для golang-nutВ , было упомянуто, что Go не очень хорошо справляется с неоднозначностью наследования. Я скорректировал упомянутый там код, чтобы он отображал известную «проблему ужасного бриллианта»:

package main

import "fmt"

type T1 struct {
    T2
    T3
}

type T2 struct {
    T4
    foo int
}

type T3 struct {
    T4
}

type T4 struct {
    foo int
}

func main() {
    t2 := T2{ T4{ 9000 }, 2 }
    t3 := T3{ T4{ 3 } }
    fmt.Printf("foo=%d\n", t2.foo)
    fmt.Printf("foo=%d\n", t3.foo)
    t1 := T1{
        t2,
        t3,
    }
    fmt.Printf("foo=%d\n", t1.foo)
}

Запустите приведенный выше код онлайн

Приведенный выше код не компилируется с какими-либо предупреждениями или ошибками.Это аналогичный код C++, как вы можете видеть, это не скомпилируется из-за двусмысленности.

Каков будет результат? Во-первых, я думаю, что при множественном наследовании слово «простой» вряд ли можно использовать для описания этого языка программирования.После того, как я увидел приведенный выше код, никто не смог убедить меня, что Go — один из самых простых языков, даже простых языков.Нет даже некоторых других вещей, которые вы можете сделать с внедрением, таких как внедрение через указатели или внедрение через указатели на интерфейсы. (Я даже не уверен, что на самом деле означают эти функции.)

Во-вторых, я хочу сделать краткую критику самого языка Go. Отсутствие обработки такой двусмысленности кажется ошибкой дизайна или реализации. Даже C++ не настолько сумасшедший, чтобы компилировать такой код. Этого достаточно, чтобы вам кое-что сказать.

5. Обработка ошибок

Различная обработка ошибок обычно приводит к огромной словесной перепалке. Я не хочу об этом говорить. Я использовал все распространенные стили обработки ошибок на разных языках (я так думаю), и мне не все они нравятся. Я думаю, что обработка ошибок независимо от того, что всегда былоPITA(Аннотация: Это должна быть иностранная метафора). Чтобы поменять один стиль на другой, вы просто меняете один набор вопросов на другой. Нет хорошего пути.

Вернемся к простым вещам: Go упростил задачу, предоставив мне возможность не использовать исключения. Функция многократного возвращаемого значения не упрощает задачу, а это означает, что вы не можете вернуть ошибку или результат успеха, вы можете вернуть все или ничего (CSтерминологии, можно сказать, что вопрос относится к типу продукта, а не к сумме). На самом деле, я видел много обзоров кода для новичков.

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

Еще одна непростая – это паника. Не поймите меня неправильно, я понимаю, почему он существует в Go и его полезность, на самом деле другие языки имеют аналогичную обработку. Я привожу это только как аргумент против простоты. ИМХО, для новичка, скорее всего, будет запутаться в разнице между error и panic и когда какую использовать.

6. Дженерики

Эта тема, вероятно, является большим червем, чем обработка ошибок.

Как и в случае с ошибками, здесь я просто хочу подумать о сложности или простоте. Многие в сообществе Go, кажется, думают, что дженерики по своей сути сложны (=плохо, эммммммм) с огромными накладными расходами того или иного рода. В какой-то степени это правда, но я не думаю, что это так плохо, как описывают некоторые люди. Кажется, что эти люди испыталиC++Боль шаблона, и с тех пор всякий раз, когда упоминаются дженерики, начинается ПТСР (посттравматическое стрессовое расстройство).

увидеть людей здесь,Дженерики не монстр. Конечно, они никогда не должны быть такими,C++Такой сложный (или какой-то другой странный язык). Я имею в виду, что даже фронтендеры некоторое время работали с дженериками (TypeScript, Flow,...), и если они не боятся дженериков, то и другим программистам незачем бояться :) (извините, фронтенд-разработчики, просто шучу.)

Люди не понимают, что при правильном использовании обобщения могут значительно упростить использование многих типов и функций. Например, рассмотримИнтерфейс сваи. Вот как объявляется интерфейс из кучи:

popped := heap.Pop(&someheap)
myfoo := popped.(*Foo)       // ZOMG what just happened here?

Объясните это новичкам, в том числе проблему паники. Может быть, подумать об этом, если они действительно не помещают всеinterface{}Поймите это правильно, так что происходит. В отличие:

myfoo := heap.Pop(&someheap) // myfoo has the correct type

Его легче читать, легче объяснить (вы объясняете так, как хотели бы).mapТипы уже существуют в Go! ). И также труднее напортачить при написании кода.

Недостаток дженериков - это то, почему дополнительная сложность, которая также вызывает значительную сложность в других частях прохождения, в основном требует различной «магической» функции / типа.map,sliceиchannelвиды магии и сопутствующиеmake()функция, которая является конструктором для всех трех из них.sliceТипы могут использоваться как в качестве ссылок на массивы, так и в качестве динамических массивов. (Что бы ни случилось, «делай что-то одно и делай это хорошо»?)

(Просто чтобы напомнить всем, что я не против этого, просто упоминаю об этом ради нетривиального аргумента.)

7. Другие

Думаю, я исключил основные простые нарушения. В моем списке всего несколько простых:

  1. <-и->оператор. это может быть простоchannelвид метода.
  2. iota- В принципе то же самое, но странное перечисление.
  3. Встроенное множественное число.
  4. если поддерживает короткие операторы(Иногда полезно, ноifСинтаксис сложнее, чем в других языках)

Я думаю, это все. Наверное что-то забыл, но думаю хватит.

Итак, мне кажется, что на самом деле приносит Go, если не простота?

Задачи  -  "горутины"

Это может показаться немного очевидным, потому чтоgoroutines— часто упоминаемая функция, такая как «простота», поэтому я думаю, что необходимо провести различие: я не думаю, что это параллелизм в обычном смысле, и его нельзя считать сильной стороной Go. Не поймите меня неправильно, с параллелизмом в Go все в порядке. Просто говорю, что ничего особенного. У вас есть каналы, что определенно хорошо, но в основном это просто одновременные очереди, которые я использовал в другом месте. Затем у вас есть обычные примитивы параллелизма, такие как мьютексы, блокировки чтения-записи, условные переменные и т. д. Вы можете синхронизировать свой код, и вы можете столкнуться с условиями гонки и взаимоблокировками, как и многие другие языки.

мне нравитсяgoroutines(Помимо очевидного факта, что они являются облегченными потоками пользовательского пространства) заключается в том, как они могут использовать ввод-вывод — то, как они планируют подключения к низкоуровневым API-интерфейсам ввода-вывода хост-ОС (таким как epoll, kqueue, IOCP...). Программистам часто сложно сделать что-то приятное и полезное, особенно при компиляции нативных языков. Я все еще получаю здесь подробности, но, на мой взгляд, это хорошая практика, и именно поэтому я вижу Go как светлое пятно для будущих инженеров.

Как уже упоминалось, мне также нравится Go как язык, который компилируется в нативный код. Приятно видеть, что новые языки используют сборку мусора для поддержания этого невероятного эффекта. (или другие формы автоматического управления памятью -Swiftупомянул)

в заключении

Итак, читатели, почему все это вас покинуло? Go сложный или что-то еще?

Конечно нет, точно не нравитсяC++илиHaskellКак сложный. В отличие от Go действительно очень просто. С другой стороны, сравнение Go и других распространенных языков (таких какJava,JavaScript,Pythonд.), ситуация менее ясна, как я и надеялся. (Кроме того, это сложная, нечетко определенная задача.)

Могу привести аналогичный пример. Go может быть проще этих языков в некоторых отношениях, в некоторых нет... Грубо говоря, я бы сказал, что это средний показатель для других широко используемых языков. Я также не думаю, что простота, как на ощупь, так и в реальном использовании, имеет значение в конечном опыте.

Наконец, откуда эта статья и кто ее автор? Я не уверен. Я пока не знаю, будет ли Go выбран в качестве (под)проекта в моей повседневной работе или я могу использовать его в качестве хобби. Я не хочу быть частью догматической работы с сообществом, подобной той, что упоминается в этой статье. Есть ли идеологически ориентированное место? Не стесняйтесь вносить предложения по этому поводу.

я иRustУ сообщества та же проблема, не обращайте на это внимания, я также знаю, что было бы лучше оставить тех, кто более ярых сторонников. (Вопрос: «Можете ли выRustПереписать свой проект? "A: "Потерянный") Может быть, это природа этих новых языков и их борьба за то, чтобы вдохновлять людей, так вдохновляющее солнце.