• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Konstantin8105/Effective_Go_RU: Перевод - Эффективный Go

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

Konstantin8105/Effective_Go_RU

开源软件地址:

https://github.com/Konstantin8105/Effective_Go_RU

开源编程语言:

HTML 100.0%

开源软件介绍:

Effective Go (RU) (Эффективный Go)


Оригинал смотри: https://golang.org/doc/effective_go.html go version go1.7.4


Список дополнительных материалов:


Оглавление


Введение

^

Go - это новый язык программирования. Хотя, он заимствует идеи из существующих языков, он обладает необычными свойствами, которые позволяют создавать эффективные программы, язык Go отличается по своему характеру от программ, написанных на родственных языках. Прямолинейный перевод C++ или Java программ в Go вряд ли даст удовлетворительный результат, т.к. Java программы написаны на Java, не на Go. С другой стороны, думая о проблеме с точки зрения Go можно добиться успеха, но это уже другая программа. Другими словами, для хорошего написания кода на языке Go, важно понимать его особенности и идиомы. Также важно знать установленные соглашения для программирования на Go, такие как именование, форматирование, разработка программ и так далее, так чтобы программы написанные Вами были простыми для понимания другими программистами Go.

Этот документ даёт примеры для написания чистого, идеоматичного кода на Go. Он дополняет спецификацию языка, Тур по Go, и Как писать на Go, каждую из которых необходимо прочитать в первую очередь.

^

Примеры

^

Go пакеты исходных кодов предназначены не только в качестве основных библиотек, но и в качестве примеров использования языка. Кроме того, многие пакеты имеют работающие, автономные исполняемые примеры и Вы можете запустить напрямую с помощью страницы golang.org, такие как этот (если необходимо, нажмите на слово "Примеры" чтобы открыть их). Если у Вас есть вопрос о том как решить какую-либо проблему или как что-то реализовать, то документация, исходные коды и примеры в библиотеке могут дать ответ, идею или объяснение.

^

Форматирование

^

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

В Go мы используем нетипичный подход и передаем машине заботу о форматировании. Программа gofmt (также доступна, как go fmt, которая производит действия на уровне пакета, а не на уровне файлов) читает код на Go и выпускает исходный код со стандартным стилем отступов и вертикальным выравниванием, сохраняет, и при необходимости, переформатирует комментарии. Если Вы хотите знать, как по-новому структурировать код, запустите gofmt; если структура неверна, gofmt поправит Вашу программу (или файл сообщит об ошибке gofmt), не работайте в обход форматирования программой gofmt.

К примеру, нет необходимости тратить время на выравнивание комментариев для полей структур, т.к. gofmt сделает это за Вас. Для данного фрагмента кода

type T struct {
    name string // name of the object
    value int // its value
}

gofmt произведет выравнивание по колонкам:

type T struct {
    name    string // name of the object
    value   int    // its value
}

Все стандартные пакеты Go отформатированы с помощью gofmt.

Очень коротко о некоторых деталях форматирования:

Абзац

Мы используем табуляцию для абзацев и gofmt делает это по умолчанию. Используйте пробелы только при острой необходимости.

Длина строки

Go не имеет предела длины строки. Не беспокойтесь о длинных строках. Если строка кажется слишком длинной, прервите ее и добавьте дополнительный отступ (символ табуляции) на новой строке.

Круглые скобки

Go нуждается в меньшем количестве круглых скобок, чем C и Java: структуры ветвления, цикла ( if , for , switch) не имеют круглых скобок в своём синтаксисе. Также, иерархия операторов стала проще и короче. К примеру, выражение

x<<8 + y<<16

не нуждается в добавлении пробелов, в отличии от других языков.

^

Комментарии

^

Go использует C-стиль /* */ для блока комментариев и C++-стиль // для однострочных комментариев. Как правило, используются однострочные комментарии. Блок комментариев, в основном, используется при комментировании пакетов, но также для выразительности или отключения большого участка кода.

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

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

/*
Package regexp implements a simple library for regular expressions.

The syntax of the regular expressions accepted is:

    regexp:
        concatenation { '|' concatenation }
    concatenation:
        { closure }
    closure:
        term [ '*' | '+' | '?' ]
    term:
        '^'
        '$'
        '.'
        character
        '[' [ '^' ] character-ranges ']'
        '(' regexp ')'
*/
package regexp

Если пакет простой, то комментарий может быть кратким.

// Package path implements utility routines for
// manipulating slash-separated filename paths.

Дополнительное форматирование, к примеру баннер из * (звездочек), не требуется. Шрифт для сформированного результата не обязательно будет моноширинный, поэтому не полагайтесь на пробелы при выравнивании, godoc, также как gofmt, позаботятся об этом. Комментарии интерпретируются как простой текст, поэтому HTML и другие аннотации такие как _эта_ воспроизводятся дословно и поэтому не должны использоваться. Единственное исключение, которое делает godoc, это выделение моноширинным шрифтом участков кода с отступами. Хорошим примером такого исключения является комментарий к пакету fmt.

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

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

Лучше всего использовать комментарии в виде полных предложений. Это позволяет производить их автоматическую обработку. Первое предложение должно быть ключевым и начинаться с имени объявления.

// Compile parses a regular expression and returns, if successful,
// a Regexp that can be used to match against text.
func Compile(str string) (*Regexp, error) {

Если комментарий начинается с имени, то godoc может с использоваться совместно с grep. Представьте, что Вы не можете вспомнить имя "Compile", но Вы ищите the parsing function для регулярных выражений и тогда Вы можете выполнить команду:

$ godoc regexp | grep -i parse

Если все комментарии в пакете начинаются с "This function...", grep не сможет помочь с поиском имени. Если же комментарии начинаются с имени, Вы можете увидеть что-то вроде следующего результата, который напомнит Вам о том, что Вы искали.

$ godoc regexp | grep parse
    Compile parses a regular expression and returns, if successful, a Regexp
    parsed. It simplifies safe initialization of global variables holding
    cannot be parsed. It simplifies safe initialization of global variables
$

Синтаксис Go допускает групповое объявление. Для каждой группы констант или переменных может быть представлен один общий комментарий. Однако такое объявление выглядит небрежно.

// Error codes returned by failures to parse an expression.
var (
    ErrInternal      = errors.New("regexp: internal error")
    ErrUnmatchedLpar = errors.New("regexp: unmatched '('")
    ErrUnmatchedRpar = errors.New("regexp: unmatched ')'")
    ...
)

Группировка также может показать взаимосвязи между элементами, к примеру, группа переменных защищенных mutex:

var (
    countLock   sync.Mutex
    inputCount  uint32
    outputCount uint32
    errorCount  uint32
)

^

Именование

^

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

Именование пакетов

^

Когда пакет импортируется, имя пакета используется для доступа к его содержимому. После того, как пакет импортирован,

import "bytes"

можно использовать bytes.Buffer. Это полезно, если все, кто использует пакет, могут использовать одно и то же имя, для обращения к его содержимому, подразумевается, что имя пакета должно быть коротким, четким и запоминающимся. В соответствии с соглашением,имена пакетов состоят из одного слова в нижнем регистре; нет необходимости в использовании подчеркиваний или СмешанногоРегистра. При выборе длинного имени пакета, всем, кто будет его использовать, придётся писать это имя. Но не беспокойтесь об уникальности имени. Имя пакета только по умолчанию используется при импорте; оно не должно быть глобально уникальным, и в редких случаях, при импорте может быть указано другое имя. В любом случае, путаница встречается редко, так как имя файла в импорте определяет, какой именно пакет используется.

Согласно другому соглашению, имя пакета является базовым именем его исходного каталога; пакет src/encoding/base64 импортируется как "encoding/base64" и имеет название base64, а не encoding_base64 и не encodingBase64.

Импортирующий пакет будет использовать имя пакета для обозначения его содержимого, поэтому при экспорте может учитываться этот факт, чтобы избежать повторения. (Не используйте import ., это, конечно, может упростить запуск тестов вне пакета, но в других случаях использоваться не должно). Например, тип reader для буферного чтения описанный в пакете bufio называется Reader, а не BufReader, т.к пользователи его видят как bufio.Reader, имя которого кратко и понятно.

Более того, т.к. импортируемые объекты адресуются по имени пакета, следовательно bufio.Reader не будет конфликтовать с io.Reader. Аналогично, функция для создания нового экземпляра объекта ring.Ring, которая объявлена как конструктор в Go, может называться NewRing, но т.к. Ring - это экспортируемый тип из пакета ring, функция-конструктор может называться просто New, которую, можно будет вызвать как ring.New. Используйте структуру пакетов при выборе имен.

Другой короткий пример функция once.Do; once.Do(setup) читается хорошо, и при этом лучше не станет, если ее переименовать в once.DoOrWaitUntilDone(setup). Длинные имена не делают названия более читабельными. В то время как комментарии могут быть более ценным, чем длинные имена.

Геттеры

^

Go не предоставляет автоматическую поддержку геттеров и сеттеров. Но не будет ошибкой создание геттеров и сеттеров самостоятельно, и если это необходимо, то делайте так, но идиоматически нет необходимости добавлять Get в имя геттера. Если у Вас есть поле с именем owner (с маленькой буквы, неэкспортируемое), то геттер может называться Owner (с большой буквы, экспортируемый), а не GetOwner. Использование имен, начинающихся с заглавной буквы, позволяет отделить экспортируемые методы от неэкспортируемых полей. Cеттер, при необходимости, может быть назван SetOwner. Оба примера в следующем коде:

owner := obj.Owner()
if owner != user {
    obj.SetOwner(user)
}

Имена интерфейсов

^

По соглашению, интерфейсы с одним методом должны называться как метод с суффиксом -er или подобно этому, для образования существительного: Reader, Writer, Formatter, CloseNotifier и т.д.

Существует целый ряд имен, которыe соблюдают это соглашение и содержат подобные методы. Read , Write , Close, Flush, String и т.д., имеют канонические подписи и значения. Чтобы избежать путаницы, не давайте методу ни одного из этих имен, если оно не имеет ту же сигнатуру и значение. С другой стороны, если ваш тип реализует метод с тем же значением, как и метод хорошо известного типа, то дайте ему то же имя и значение; назовите Ваш метод конвертации в строку String , а не ToString.

MixedCaps

^

В заключении, Go соглашение использует MixedCaps или mixedCaps , а не подчеркивание для имен из нескольких слов.

Точка с запятой

^

Как и в С, грамматика Go формально использует точку с запятой для разделения операций-выражений (инструкций), но в отличии от C, точка с запятой не представлена в исходном коде. Вместо этого, лексер использует простое правило добавления точки с запятой автоматически, при сканировани. Таким образом текст на входе по большей части освобожден от них.

Правило такое. Если последний токен(лексема) перед символом новой строки - идентификатор (который включает такие слова, как int и float64), базовый литерал, такой как число или строковая константа, или один из нижеперечисленных токенов

break continue fallthrough return ++ -- ) }

то, лексер всегда добавляет точку с запятой после него. Вкратце, это может звучать так: "Если новая строка начинается после токена, который может закрывать операцию-выражение, то добавить точку с запятой".

Точка с запятой также может быть опущена сразу перед закрывающей скобкой, таким образом для операции-выражения такой как:

     go func() { for { dst <- <-src } }()

точка с запятой не требуется.

Как следствие из правила, вы не можете перенести открывающую скобку управляющих структур (if, for, switch или select) на новую строку. Если перенесете, точка с запятой будет вставлена перед скобкой, которая может стать причиной нежелательных эффектов. Пишите так,

if i < f() {
    g()
}

но не так

if i < f()  // ошибка!
{           // ошибка!
    g()
}

^

Управляющие структуры

^

Управляющие структуры в Go аналогичны тем же структурам в C, но имеют ряд важных отличий. Во-первых нет циклов do и while, есть лишь обобщенный for. Во-вторых, switch более гибкий. В-третьих if и switch имеют опциональную инициализацию переменных, как и в for. В-четвертых, break и continue опционально принимают метку, к которой необходимо перейти. В-пятых, есть новые операторы, такие как типизированный switch и многоканальный select. Синтаксис также немного отличается: отсутствуют круглые скобки в условии, и тело структуры всегда должно быть ограничено фигурными скобками.

^

If

^

В Go простой if выглядит так:

if x > 0 {
    return y
}

Обязательные фигурные скобки упрощают написание простых условий if на несколько строк. Это хороший стиль в любом случае, особенно когда тело содержит управляющие операторы, такие как return или break.

Поскольку if и switch допускают инициализацию переменных, то часто можно видеть подобную запись:

if err := file.Chmod(0664); err != nil {
    log.Print(err)
    return err
}

В библиотеках Go, вы найдёте подобную запись, если if не переходит в следующий блок, т.е. в теле используется break, continue, goto или return, а необязательный else опускается.

f, err := os.Open(name)
if err != nil {
    return err
}
codeUsing(f)

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

f, err := os.Open(name)
if err != nil {
    return err
}
d, err := f.Stat()
if err != nil {
    f.Close()
    return err
}
codeUsing(f, d)

^

Переопределение и переприсваивание

^

Последний пример предыдущего раздела демонстрирует использование краткой формы объявления переменных :=. Вызов os.Open объявляет сразу две переменных f и err

f, err := os.Open(name)

Несколькими строками ниже вызывается f.Stat,

d, err := f.Stat()

который выглядит как объявления двух переменных d и err. Хотя err присутствует в обоих объявлениях. Это дублирование вполне законно: err объявляется в первом случае, и лишь переприсваивается во втором. Это означает, что f.Stat использует уже существующую переменную err, определенную выше, и просто присваивает ей новое значение.

В объявлении := переменная v может присутствовать, даже если она уже объявлена, при условии:

  • если объявление происходит в той же самой области видимости, что и существующ

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
CodisLabs/codis: Proxy based Redis cluster solution supporting pipeline and scal ...发布时间:2022-06-13
下一篇:
google/go-jsonnet发布时间:2022-06-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap