Примечания к выпуску Go 1

Введение в Go 1

Версия Go 1, или просто Go 1, определяет язык и набор основных библиотек, обеспечивающих стабильную основу для создания надежных продуктов, проектов и публикаций.

Основной мотивацией создания Go 1 является стабильность для её пользователей. Люди должны иметь возможность писать программы на Go и ожидать, что они будут продолжать компилироваться и выполняться без изменений в течение многих лет, включая производственные среды, такие как Google App Engine. Аналогично, люди должны мочь писать книги о Go, указывать, какая версия Go описывается в книге, и иметь уверенность, что номер этой версии останется значимым через много лет.

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

Go 1 — это представление языка Go в его текущем состоянии, а не полное переосмысление языка. Мы избегали проектирования новых функций и вместо этого сосредоточились на устранении проблем и несоответствий, а также на улучшении переносимости. Существует ряд изменений в языке Go и пакетах, которые мы рассматривали длительное время и прототипировали, но не выпускали, в основном потому, что они являются значительными и несовместимыми с предыдущими версиями. Go 1 дал нам возможность выпустить их, что полезно в долгосрочной перспективе, но также означает, что Go 1 вводит несовместимости для старых программ. К счастью, инструмент go fix может автоматизировать большую часть работы, необходимой для приведения программ к стандарту Go 1.

Этот документ описывает основные изменения в Go 1, которые повлияют на программистов, обновляющих существующий код; его ориентиром является предыдущий релиз r60 (обозначенный как r60.3). Также он объясняет, как обновить код с r60 для запуска под Go 1.

Изменения в языке

Append

Предварительно объявленная вариадическая функция append позволяет легко расширять срез, добавляя элементы в конец. Распространённое использование — добавление байтов в конец байтового среза при генерации вывода. Однако append не предоставляла способа добавить строку в []byte, что также является распространённым случаем.

greeting := []byte{}
greeting = append(greeting, []byte("hello ")...)

По аналогии со схожим свойством функции copy, Go 1 позволяет напрямую добавлять (по байтам) строку в байтовый срез, уменьшая разрыв между строками и байтовыми срезами. Преобразование больше не требуется:

greeting = append(greeting, "world"...)

Обновление: Это новая функция, поэтому существующий код не нуждается в изменениях.

Close

Предварительно объявленная функция close предоставляет механизм, с помощью которого отправитель может сигнализировать о том, что больше никаких значений отправляться не будет. Это важно для реализации циклов for range по каналам и полезно в других ситуациях. Частично по дизайну и частично из-за гонок, которые могут возникнуть иначе, предназначена она исключительно для использования горутиной, отправляющей данные в канал, а не для горутины, получающей данные. Тем не менее, до Go 1 не существовало проверки на этапе компиляции, которая бы убедилась, что close используется правильно.

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

var c chan int
var csend chan<- int = c
var crecv <-chan int = c
close(c)     <span class="comment">// legal</span>
close(csend) <span class="comment">// legal</span>
close(crecv) <span class="comment">// illegal</span>

Обновление: Существующий код, пытающийся закрыть канал только для получения, был ошибочным даже до Go 1 и должен быть исправлен. Компилятор теперь будет отклонять такой код.

Составные литералы

В Go 1 составной литерал типа массива, среза или карты может опускать указание типа для инициализаторов элементов, если они имеют тип указателя. Все четыре инициализации в этом примере являются допустимыми; последняя была недопустимой до Go 1.

type Date struct {
  month string
  day   int
}
<span class="comment">// Значения структур, полностью указаны; всегда допустимо.</span>
holiday1 := []Date{
  Date{"Feb", 14},
  Date{"Nov", 11},
  Date{"Dec", 25},
}
<span class="comment">// Значения структур, тип опущен; всегда допустимо.</span>
holiday2 := []Date{
  {"Feb", 14},
  {"Nov", 11},
  {"Dec", 25},
}
<span class="comment">// Указатели, полностью указаны, всегда допустимо.</span>
holiday3 := []*Date{
  &Date{"Feb", 14},
  &Date{"Nov", 11},
  &Date{"Dec", 25},
}
<span class="comment">// Указатели, тип опущен; допустимо в Go 1.</span>
holiday4 := []*Date{
  {"Feb", 14},
  {"Nov", 11},
  {"Dec", 25},
}

Обновление: Это изменение не влияет на существующий код, но команда gofmt -s, примененная к существующему исходному коду, среди прочего, будет опускать явные типы элементов там, где это разрешено.

Горутины во время инициализации

В старом языке определялось, что инструкции go, выполняемые во время инициализации, создавали горутины, но они не начинали выполняться до завершения инициализации всей программы. Это вызывало неудобства в множестве мест и, по сути, ограничивало полезность конструкции init: если было возможно, что другой пакет использует библиотеку во время инициализации, библиотека была вынуждена избегать использования горутин. Этот дизайн был сделан по причинам простоты и безопасности, но, по мере роста уверенности в языке, показалось, что это стало излишним. Запуск горутин во время инициализации не более сложен или небезопасен, чем запуск во время обычного выполнения.

В Go 1 код, использующий горутины, может вызываться из инструкций init и глобальных выражений инициализации без риска возникновения взаимной блокировки (deadlock).

var PackageGlobal int

func init() {
  c := make(chan int)
  go initializationFunction(c)
  PackageGlobal = <-c
}

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

Тип rune

Спецификация языка разрешает тип int быть шириной 32 или 64 бита, однако текущие реализации устанавливают int равным 32 битам даже на 64-битных платформах. Было бы предпочтительнее, чтобы int был 64 битами на 64-битных платформах. (Существуют важные последствия для индексации больших срезов.) Однако, это изменение привело бы к потере пространства при обработке символов Юникода с помощью старого языка, потому что тип int также использовался для хранения кодовых точек Юникода: каждая кодовая точка будет терять дополнительные 32 бита памяти, если int увеличится с 32 до 64 бит.

Чтобы сделать изменение на 64-битный int возможным, Go 1 вводит новый базовый тип, rune, для представления отдельных кодовых точек Юникода. Он является псевдонимом для int32, аналогично тому, как byte является псевдонимом для uint8.

Литералы символов, такие как 'a', '語' и '\u0345', теперь имеют тип по умолчанию rune, аналогично тому, как 1.0 имеет тип по умолчанию float64. Переменная, инициализированная литералом символа, будет иметь тип rune, если только это не указано иначе.

Библиотеки были обновлены для использования rune вместо int тогда, когда это уместно. Например, функции unicode.ToLower и связанные с ними теперь принимают и возвращают rune.

delta := 'δ' <span class="comment">// delta имеет тип rune.</span>
var DELTA rune
DELTA = unicode.ToUpper(delta)
epsilon := unicode.ToLower(DELTA + 1)
if epsilon != 'δ'+1 {
  log.Fatal("несогласованный регистр для греческого")
}

Обновление: Большинство исходного кода не пострадают от этого изменения, поскольку вывод типа из инициализаторов := вводит новый тип бесшумно, и он распространяется оттуда. Некоторый код может получить ошибки типов, которые можно исправить с помощью простого преобразования.

Тип error

Go 1 вводит новый встроенный тип, error, который имеет следующее определение:

<code>    type error interface {
  Error() string
}
</code>

Поскольку последствия этого типа находятся полностью в библиотеках пакетов, он обсуждается ниже.

Удаление из карт

В старом языке, чтобы удалить запись с ключом k из карты m, нужно было написать инструкцию,

<code>    m[k] = value, false
</code>

Этот синтаксис был необычным особым случаем — единственным двузначным присваиванием. Он требовал передачи значения (обычно игнорируемого), которое оценивалось, но затем отбрасывалось, плюс булево значение, которое почти всегда было константой false. Он выполнял свою работу, но был странным и вызывал споры.

В Go 1 этот синтаксис упразднён; вместо этого появилась новая встроенная функция delete. Вызов

delete(m, k)

удалит запись из карты, полученную выражением m[k]. Возвращаемого значения нет. Попытка удалить несуществующую запись — это просто noop.

Обновление: Запуск go fix преобразует выражения вида m[k] = value, false в delete(m, k), если очевидно, что игнорируемое значение может быть безопасно удалено из программы, а false ссылается на предопределённую булеву константу. Инструмент fix также пометит другие случаи использования этого синтаксиса для проверки программистом.

Итерация по картам

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

В Go 1 порядок, в котором элементы посещаются при итерации по карте с использованием инструкции for range, определён как непредсказуемый, даже если тот же цикл запускается несколько раз с одной и той же картой. Код не должен полагаться на какой-либо конкретный порядок посещения элементов.

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

m := map[string]int{"Sunday": 0, "Monday": 1}
for name, value := range m {
  <span class="comment">// Эта итерация не должна предполагать, что Sunday будет посещён первым.</span>
  f(name, value)
}

Обновление: Это изменение — одно из тех, где инструменты не могут помочь. Большинство существующего кода останется без изменений, но некоторые программы могут сломаться или вести себя неправильно; рекомендуется вручную проверить все инструкции range над картами, чтобы убедиться, что они не зависят от порядка итерации. В стандартном репозитории были найдены несколько таких примеров — они уже исправлены. Обратите внимание, что ранее уже было неправильно полагаться на порядок итерации, поскольку он был не определён. Это изменение формализует непредсказуемость.

Множественное присваивание

Спецификация языка давно гарантировала, что в присваиваниях выражения справа вычисляются полностью до того, как выражения слева будут присвоены. Чтобы гарантировать предсказуемое поведение, Go 1 уточняет спецификацию ещё больше.

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

В следующих примерах показано поведение.

sa := []int{1, 2, 3}
i := 0
i, sa[i] = 1, 2 <span class="comment">// устанавливает i = 1, sa[0] = 2</span>

sb := []int{1, 2, 3}
j := 0
sb[j], j = 2, 1 <span class="comment">// устанавливает sb[0] = 2, j = 1</span>

sc := []int{1, 2, 3}
sc[0], sc[0] = 1, 2 <span class="comment">// устанавливает sc[0] = 1, затем sc[0] = 2 (итог: sc[0] = 2)</span>

Обновление: Это изменение не может быть исправлено инструментами, но вероятность поломки крайне мала. Никакой код в стандартном репозитории не был нарушен этим изменением, и код, зависящий от предыдущего неописанного поведения, уже был некорректным.

Возврат значений и переменные, скрывающие другие переменные

Частая ошибка — использовать инструкцию return (без аргументов) после присваивания переменной с тем же именем, что и у переменной результата, но являющейся другой переменной. Такая ситуация называется скрытием (shadowing): переменная результата была скрыта другой переменной с тем же именем, объявленной в более внутренней области видимости.

В функциях с именованными возвращаемыми значениями, компиляторы Go 1 запрещают использование инструкций return без аргументов, если любая из именованных возвращаемых переменных скрыта в точке инструкции return. (Это не часть спецификации, потому что это область, которую мы всё ещё исследуем; ситуация аналогична тому, как компиляторы отвергают функции, не заканчивающиеся явной инструкцией return.)

Эта функция неявно возвращает скрытое значение и будет отвергнута компилятором:

func Bug() (i, j, k int) {
  for i = 0; i < 5; i++ {
    for j := 0; j < 5; j++ { <span class="comment">// Перезаписывает j.</span>
    k += i * j
    if k > 100 {
      return <span class="comment">// Отклонено: j скрыта здесь.</span>
    }
  }
}
return <span class="comment">// OK: j не скрыта здесь.</span>
}

Обновление: Код, который скрывает таким образом возвращаемые значения, будет отвергнут компилятором и потребует ручного исправления. В стандартном репозитории возникли лишь немногие случаи, которые в основном были ошибками.

Копирование структур с неэкспортированными полями

В старом языке пакет не мог создать копию значения структуры, содержащей неэкспортированные поля другого пакета. Однако существовала обязательная исключение для получателя метода; кроме того, реализации copy и append никогда не соблюдали это ограничение.

В Go 1 пакеты смогут копировать значения структур, содержащих неэкспортированные поля из других пакетов. Помимо устранения несоответствия, это изменение позволяет создавать новый тип API: пакет может возвращать прозрачное значение, не прибегая к указателю или интерфейсу. Новые реализации time.Time и reflect.Value являются примерами типов, использующих это новое свойство.

В качестве примера, если пакет p включает определения,

<code>    type Struct struct {
  Public int
  secret int
}
func NewStruct(a int) Struct {  // Note: not a pointer.
return Struct{a, f(a)}
}
func (s Struct) String() string {
  return fmt.Sprintf("{%d (secret %d)}", s.Public, s.secret)
}
</code>

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

<code>    import "p"

myStruct := p.NewStruct(23)
copyOfMyStruct := myStruct
fmt.Println(myStruct, copyOfMyStruct)
</code>

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

Обновление: Это новая функция, поэтому существующий код не требует изменений.

Равенство

До Go 1 язык не определял равенство для значений структур и массивов. Это означало, между прочим, что структуры и массивы не могли использоваться в качестве ключей карт. С другой стороны, Go определял равенство для значений функций и карт. Равенство функций было проблематичным в присутствии замыканий (когда два замыкания равны?) в то время как равенство карт сравнивало указатели, а не содержимое карт, что обычно не то, чего хотел пользователь.

Go 1 решает эти проблемы. Во-первых, структуры и массивы могут сравниваться на равенство и неравенство (== и !=), и поэтому могут использоваться в качестве ключей карт, при условии, что они состоят из элементов, для которых также определено равенство, с использованием поэлементного сравнения.

type Day struct {
  long  string
  short string
}
Christmas := Day{"Christmas", "XMas"}
Thanksgiving := Day{"Thanksgiving", "Turkey"}
holiday := map[Day]bool{
  Christmas:    true,
  Thanksgiving: true,
}
fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])

Во-вторых, Go 1 удаляет определение равенства для значений функций, за исключением сравнения с nil. Наконец, равенство карт тоже исчезло, также за исключением сравнения с nil.

Обратите внимание, что равенство по-прежнему не определено для срезов, для которых вычисление в общем случае невозможно. Также обратите внимание, что упорядоченные операторы сравнения (< <= > >=) по-прежнему не определены для структур и массивов.

Обновление: Равенство структур и массивов — новая функция, поэтому существующий код не требует изменений. Существующий код, который зависит от равенства функций или карт, будет отвергнут компилятором и потребует ручного исправления. Мало программ будет затронуто, но исправление может потребовать некоторого переконструирования.

Иерархия пакетов

Go 1 устраняет множество недостатков старой стандартной библиотеки и очищает несколько пакетов, делая их более внутренне согласованными и переносимыми.

В этом разделе описывается, как были перераспределены пакеты в Go 1. Некоторые из них были перемещены, некоторые переименованы, а некоторые удалены. Новые пакеты описываются в последующих разделах.

Иерархия пакетов

В Go 1 была изменена иерархия пакетов, которая группирует связанные элементы в подкаталоги. Например, utf8 и utf16 теперь находятся в подкаталогах unicode. Кроме того, некоторые пакеты были перемещены в подрепозитории code.google.com/p/go, в то время как другие были полностью удалены.

Старый путь Новый путь

asn1 encoding/asn1
csv encoding/csv
gob encoding/gob
json encoding/json
xml encoding/xml

exp/template/html html/template

big math/big
cmath math/cmplx
rand math/rand

http net/http
http/cgi net/http/cgi
http/fcgi net/http/fcgi
http/httptest net/http/httptest
http/pprof net/http/pprof
mail net/mail
rpc net/rpc
rpc/jsonrpc net/rpc/jsonrpc
smtp net/smtp
url net/url

exec os/exec

scanner text/scanner
tabwriter text/tabwriter
template text/template
template/parse text/template/parse

utf8 unicode/utf8
utf16 unicode/utf16

Обратите внимание, что названия пакетов для старых cmath и exp/template/html были изменены на cmplx и template.

Обновление: Запуск команды go fix обновит все импорты и переименования пакетов, которые остаются внутри стандартного репозитория. Программы, импортирующие пакеты, которые больше не находятся в стандартном репозитории, необходимо будет отредактировать вручную.

Дерево пакетов exp

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

Несколько пакетов были перемещены в exp на момент выпуска Go 1:

(Типы EscapeString и UnescapeString остаются в пакете html.)

Все эти пакеты доступны под теми же именами, но с префиксом exp/: exp/ebnf и так далее.

Также тип utf8.String был перемещён в собственный пакет exp/utf8string.

Наконец, команда gotype теперь находится в exp/gotype, а ebnflint — в exp/ebnflint. Если они установлены, то теперь находятся в $GOROOT/bin/tool.

Обновление: Код, использующий пакеты из exp, должен быть обновлён вручную или же скомпилирован из установки, в которой доступен exp. Инструмент go fix или компилятор будут жаловаться на подобные использования.

Пакеты в директории old

Поскольку они устарели, пакеты, находящиеся в директории old, не будут доступны в стандартных дистрибутивах Go 1, хотя они будут доступны в виде исходного кода для разработчиков, желающих их использовать.

Пакеты в новых местоположениях:

Обновление: Код, использующий пакеты, теперь находящиеся в old, должен быть обновлён вручную или же скомпилирован из установки, в которой доступен old. Инструмент go fix будет предупреждать о таких случаях.

Удалённые пакеты

Go 1 удаляет несколько пакетов полностью:

а также команду gotry.

Обновление: Код, использующий container/vector, должен быть обновлён для использования срезов напрямую. См. Вики сообщества языка Go для некоторых предложений. Код, использующий другие пакеты (их должно быть почти ноль), потребует пересмотра.

Пакеты, перемещённые в субрепозитории

Go 1 переместила несколько пакетов в другие репозитории, обычно субрепозитории основного репозитория Go. В таблице ниже перечислены старые и новые пути импорта:

Старый Новый

crypto/bcrypt code.google.com/p/go.crypto/bcrypt
crypto/blowfish code.google.com/p/go.crypto/blowfish
crypto/cast5 code.google.com/p/go.crypto/cast5
crypto/md4 code.google.com/p/go.crypto/md4
crypto/ocsp code.google.com/p/go.crypto/ocsp
crypto/openpgp code.google.com/p/go.crypto/openpgp
crypto/openpgp/armor code.google.com/p/go.crypto/openpgp/armor
crypto/openpgp/elgamal code.google.com/p/go.crypto/openpgp/elgamal
crypto/openpgp/errors code.google.com/p/go.crypto/openpgp/errors
crypto/openpgp/packet code.google.com/p/go.crypto/openpgp/packet
crypto/openpgp/s2k code.google.com/p/go.crypto/openpgp/s2k
crypto/ripemd160 code.google.com/p/go.crypto/ripemd160
crypto/twofish code.google.com/p/go.crypto/twofish
crypto/xtea code.google.com/p/go.crypto/xtea
exp/ssh code.google.com/p/go.crypto/ssh

image/bmp code.google.com/p/go.image/bmp
image/tiff code.google.com/p/go.image/tiff

net/dict code.google.com/p/go.net/dict
net/websocket code.google.com/p/go.net/websocket
exp/spdy code.google.com/p/go.net/spdy

encoding/git85 code.google.com/p/go.codereview/git85
patch code.google.com/p/go.codereview/patch

exp/wingui code.google.com/p/gowingui

Обновление: Запуск команды go fix обновит импорты этих пакетов, чтобы использовать новые пути импорта. Установки, которые зависят от этих пакетов, должны будут установить их с использованием команды go get.

Ключевые изменения в библиотеке

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

Тип error и пакет errors

Размещение os.Error в пакете os в основном историческое: ошибки впервые появились при реализации пакета os, и на тот момент они казались связанными с системой. С тех пор стало ясно, что ошибки являются более фундаментальными по сравнению с операционной системой. Например, было бы удобно использовать Errors в пакетах, от которых зависит os, таких как syscall. Кроме того, наличие Error в os вводит множество зависимостей от os, которые в противном случае не существовали бы.

Go 1 решает эти проблемы, вводя встроенный интерфейс error и отдельный пакет errors (аналогично bytes и strings), который содержит вспомогательные функции. Он заменяет os.NewError на errors.New, что даёт ошибкам более центральное место в среде.

Так как широко используемый метод String не должен случайно удовлетворять интерфейсу error, интерфейс error использует вместо этого имя Error для этого метода:

<code>    type error interface {
  Error() string
}
</code>

Библиотека fmt автоматически вызывает метод Error, как это уже делается для String, для простой печати значений ошибок.

type SyntaxError struct {
  File    string
  Line    int
  Message string
}

func (se *SyntaxError) Error() string {
  return fmt.Sprintf("%s:%d: %s", se.File, se.Line, se.Message)
}

Все стандартные пакеты были обновлены для использования нового интерфейса; старый os.Error исчез.

Новый пакет, errors, содержит функцию

<code>func New(text string) error
</code>

для преобразования строки в ошибку. Она заменяет старую os.NewError.

var ErrSyntax = errors.New("syntax error")

Обновление: Запуск команды go fix обновит почти весь код, затронутый изменением. Код, определяющий типы ошибок с методом String, должен быть обновлён вручную, чтобы переименовать методы в Error.

Ошибки системных вызовов

Старый пакет syscall, предшествующий os.Error (и почти всему остальному), возвращал ошибки как значения типа int. В свою очередь, пакет os передавал многие из этих ошибок, такие как EINVAL, но с использованием разных наборов ошибок на каждой платформе. Такое поведение было неприятным и непереносимым.

В Go 1 пакет syscall возвращает error для ошибок системных вызовов. В Unix, реализация выполняется с помощью типа syscall.Errno, удовлетворяющего интерфейсу error и заменяющего старый os.Errno.

Изменения, затрагивающие os.EINVAL и связанные с ним, описаны в другом месте.

Обновление: Запуск команды go fix обновит почти весь код, затронутый этими изменениями. Тем не менее, большинство кода должно использовать пакет os вместо syscall, и поэтому не будет затронуто.

Время

Работа со временем всегда представляет собой сложность в языке программирования. Старый пакет time в Go имел единицы измерения int64, отсутствие реальной типобезопасности, и не различал абсолютные времена и интервалы.

Одним из самых масштабных изменений в библиотеке Go 1 стало полное переосмысление пакета time. Вместо целочисленного количества наносекунд в виде int64, и отдельного типа *time.Time для работы с человеческими единицами измерения, такими как часы и годы, теперь существуют два фундаментальных типа: time.Time (значение, поэтому знак * отсутствует), которое представляет момент времени; и time.Duration, который представляет интервал. Оба типа имеют разрешение в наносекундах. Значение Time может представлять любое время в древнем прошлом и далеком будущем, в то время как Duration может охватывать примерно ±290 лет. Существуют методы для этих типов, а также ряд полезных предопределённых констант, таких как time.Second.

Среди новых методов можно выделить, например, Time.Add, который добавляет Duration к Time, и Time.Sub, который вычитает два Time, чтобы получить Duration.

Самое важное семантическое изменение заключается в том, что эпоха Unix (1 января 1970 года) теперь актуальна только для тех функций и методов, которые упоминают Unix: time.Unix и методы Unix и UnixNano типа Time. В частности, time.Now возвращает значение time.Time, а не целочисленное количество наносекунд с эпохи Unix, как это было в старом API.

<span class="comment">// sleepUntil засыпает до указанного времени. Возвращает немедленно, если уже поздно.</span>
func sleepUntil(wakeup time.Time) {
  now := time.Now() <span class="comment">// Значение типа Time.</span>
  if !wakeup.After(now) {
    return
  }
  delta := wakeup.Sub(now) <span class="comment">// Значение типа Duration.</span>
  fmt.Printf("Sleeping for %.3fs\n", delta.Seconds())
  time.Sleep(delta)
}

Новые типы, методы и константы были распространены во всех стандартных пакетах, использующих время, таких как os и его представление временных меток файлов.

Обновление: Инструмент go fix обновит множество использований старого пакета time, чтобы использовать новые типы и методы, хотя он не заменяет значения, такие как 1e9, представляющие наносекунды в секунду. Кроме того, из-за изменений типов некоторых значений, возникающих в результате, некоторые выражения, переписанные инструментом fix, могут потребовать дальнейшей ручной правки; в таких случаях перепись будет включать правильную функцию или метод для старой функциональности, но может иметь неправильный тип или требовать дополнительного анализа.

Мелкие изменения в библиотеке

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

Пакет archive/zip

В Go 1, *zip.Writer больше не имеет метода Write. Его наличие было ошибкой.

Обновление: Немного кода, который будет затронут, будет замечен компилятором и должен быть обновлён вручную.

Пакет bufio

В Go 1, функции bufio.NewReaderSize и bufio.NewWriterSize больше не возвращают ошибку для недопустимых размеров. Если аргумент размера слишком мал или недопустим, он будет скорректирован.

Обновление: Запуск go fix обновит вызовы, которые присваивают ошибку переменной _. Вызовы, которые не будут исправлены, будут замечены компилятором и должны быть обновлены вручную.

Пакеты compress/flate, compress/gzip и compress/zlib

В Go 1, функции NewWriterXxx в compress/flate, compress/gzip и compress/zlib всегда возвращают (*Writer, error), если они принимают уровень сжатия, и *Writer в противном случае. Типы Compressor и Decompressor пакета gzip были переименованы в Writer и Reader. Тип WrongValueError пакета flate был удалён.

Обновление Запуск go fix обновит старые имена и вызовы, которые присваивают ошибку переменной _. Вызовы, которые не будут исправлены, будут замечены компилятором и должны быть обновлены вручную.

Пакеты crypto/aes и crypto/des

В Go 1, метод Reset был удалён. Go не гарантирует, что память не будет скопирована, поэтому этот метод был вводящим в заблуждение.

Типы, специфичные для шифрования *aes.Cipher, *des.Cipher и *des.TripleDESCipher, были удалены в пользу cipher.Block.

Обновление: Удалите вызовы метода Reset. Замените использование специфичных типов шифрования на cipher.Block.

Пакет crypto/elliptic

В Go 1 тип elliptic.Curve был сделан интерфейсом для разрешения альтернативных реализаций. Параметры кривой были перемещены в структуру elliptic.CurveParams.

Обновление: Существующие пользователи *elliptic.Curve должны изменить их на просто elliptic.Curve. Вызовы функций Marshal, Unmarshal и GenerateKey теперь являются функциями в пакете crypto/elliptic, которые принимают elliptic.Curve в качестве первого аргумента.

Пакет crypto/hmac

В Go 1 функции, специфичные для хэшей, такие как hmac.NewMD5, были удалены из пакета crypto/hmac. Вместо этого hmac.New принимает функцию, возвращающую hash.Hash, например md5.New.

Обновление: Запуск команды go fix выполнит необходимые изменения.

Пакет crypto/x509

В Go 1 функция CreateCertificate и метод CreateCRL в пакете crypto/x509 были изменены так, чтобы принимать interface{}, тогда как ранее они принимали *rsa.PublicKey или *rsa.PrivateKey. Это позволит реализовать другие алгоритмы открытых ключей в будущем.

Обновление: Никаких изменений не потребуется.

Пакет encoding/binary

В Go 1 функция binary.TotalSize была заменена на Size, которая принимает аргумент типа interface{} вместо reflect.Value.

Обновление: Код, который может быть затронут, будет замечен компилятором и должен быть обновлён вручную.

Пакет encoding/xml

В Go 1 пакет xml был приведён к дизайну, ближайшему к другим пакетам marshaling, таким как encoding/gob.

Старый тип Parser был переименован в Decoder и получил новый метод Decode. Также был представлен тип Encoder.

Функции Marshal и Unmarshal теперь работают со значениями типа []byte. Для работы со потоками данных используйте новые типы Encoder и Decoder.

При маршалинге или демаршалинге значений формат поддерживаемых флагов в тегах полей изменился, чтобы быть более близким к пакету json (`xml:"name,flag"`). Сопоставление, выполняемое между тегами полей, именами полей, а также именами атрибутов и элементов XML, теперь чувствительно к регистру. Если присутствует тег поля XMLName, он также должен соответствовать имени XML-элемента, который маршалируется.

Обновление: Запуск go fix обновит большинство использований пакета, кроме некоторых вызовов Unmarshal. Особое внимание следует уделить тегам полей, поскольку инструмент fix не обновит их, и если их не исправить вручную, они могут неправильно работать в некоторых случаях. Например, старый формат "attr" теперь записывается как ",attr", тогда как простой "attr" остаётся допустимым, но с другим значением.

Пакет expvar

В Go 1 функция RemoveAll была удалена. Функция Iter и метод Iter для *Map были заменены на Do и (*Map).Do.

Обновление: Большинство кода, использующего expvar, не потребует изменений. Редкий код, использовавший Iter, может быть обновлён для передачи замыкания в Do, чтобы достичь того же эффекта.

Пакет flag

В Go 1 интерфейс flag.Value немного изменился. Метод Set теперь возвращает error вместо bool для указания успешного или неудачного выполнения.

Также появился новый тип флага — Duration, предназначенный для поддержки аргументов, задающих временные интервалы. Значения таких флагов должны указываться с единицами измерения, как и форматирует time.Duration: 10s, 1h30m и т.д.

var timeout = flag.Duration("timeout", 30*time.Second, "how long to wait for completion")

Обновление: Программы, реализующие собственные флаги, потребуют небольших ручных исправлений для обновления методов Set. Флаг Duration новый и не влияет на существующий код.

Пакеты go/*

Несколько пакетов в подкаталоге go имеют немного изменённые API.

В пакетах go/scanner, go/parser, go/printer и go/doc был представлен конкретный тип Mode для флагов режима конфигурации.

Режимы AllowIllegalChars и InsertSemis были удалены из пакета go/scanner. Они в основном использовались для сканирования текста, отличного от исходных файлов Go. Вместо этого для этих целей следует использовать пакет text/scanner.

Обработчик ошибок (ErrorHandler), передаваемый в метод Init сканера, теперь представляет собой просто функцию, а не интерфейс. Тип ErrorVector был удалён в пользу уже существующего типа ErrorList, а методы типа ErrorVector были перенесены. Ранее, чтобы использовать сканер, клиент должен был встраивать ErrorVector, теперь же клиент должен самостоятельно поддерживать ErrorList.

Набор функций разбора, предоставляемых пакетом go/parser, был сокращён до основной функции разбора ParseFile и нескольких вспомогательных функций: ParseDir и ParseExpr.

Пакет go/printer поддерживает дополнительный режим конфигурации SourcePos; если он установлен, то принтер будет выводить комментарии вида //line, благодаря чему сгенерированный вывод будет содержать информацию о позиции в исходном коде. Новый тип CommentedNode может использоваться для предоставления комментариев, связанных с произвольным ast.Node (до этого только ast.File содержал информацию о комментариях).

Названия типов пакета go/doc были упрощены путём удаления суффикса Doc: PackageDoc теперь Package, ValueDocValue и так далее. Также все типы теперь последовательно имеют поле Name (или Names, в случае типа Value), а Type.Factories стало Type.Funcs. Вместо вызова doc.NewPackageDoc(pkg, importpath), документация для пакета создаётся с помощью:

<code>    doc.New(pkg, importpath, mode)
</code>

где новый параметр mode задаёт режим работы: если он установлен в AllDecls, то учитываются все объявления (не только экспортируемые). Функция NewFileDoc была удалена, а функция CommentText стала методом Text типа ast.CommentGroup.

В пакете go/token метод token.FileSet Files (первоначально возвращавший канал *token.File) был заменён на итератор Iterate, который принимает функцию в качестве аргумента.

В пакете go/build API был практически полностью заменён. Пакет по-прежнему вычисляет информацию о Go-пакете, но он больше не запускает сборку: типы Cmd и Script исключены. (Для сборки кода следует использовать новую команду go.) Тип DirInfo теперь называется Package. FindTree и ScanDir заменены на Import и ImportDir.

Обновление: Код, использующий пакеты в go, придётся обновить вручную; компилятор отклонит некорректные использования. Шаблоны, используемые совместно с любыми типами из go/doc, могут потребовать ручных исправлений; переименованные поля приведут к ошибкам во время выполнения.

Пакет hash

В Go 1 определение hash.Hash включает новый метод, BlockSize. Этот новый метод в основном используется в криптографических библиотеках.

Метод Sum интерфейса hash.Hash теперь принимает аргумент типа []byte, к которому будет добавлено значение хэша. Предыдущее поведение можно воссоздать, добавив аргумент nil в вызов.

Обновление: Существующие реализации hash.Hash должны добавить метод BlockSize. Хэши, которые обрабатывают входные данные по одному байту за раз, могут реализовать BlockSize так, чтобы он возвращал 1. Запуск команды go fix обновит вызовы метода Sum различных реализаций hash.Hash.

Обновление: Поскольку функциональность пакета новая, обновлять ничего не требуется.

Пакет http

В Go 1 пакет http был рефакторен, некоторые утилиты были перемещены в подкаталог httputil. Эти компоненты редко используются клиентами HTTP. Затронутые элементы:

Поле Request.RawURL было удалено; оно являлось историческим артефактом.

Функции Handle и HandleFunc, а также методы с аналогичными именами в ServeMux, теперь вызывают панику, если попытаться зарегистрировать один и тот же шаблон дважды.

Обновление: Запуск команды go fix обновит несколько программ, которые были затронуты, за исключением использования RawURL, которое необходимо исправить вручную.

Пакет image

Пакет image претерпел ряд небольших изменений, перестановок и переименований.

Большая часть кода, отвечающего за работу с цветами, была перемещена в собственный пакет, image/color. Для перемещённых элементов возникает симметрия; например, каждый пиксель image.RGBA представляет собой color.RGBA.

Старый пакет image/ycbcr был интегрирован с некоторыми переименованиями в пакеты image и image/color.

Старый тип image.ColorImage по-прежнему находится в пакете image, но был переименован в image.Uniform, в то время как image.Tiled был удалён.

В следующей таблице представлены все переименования.

Старое имя Новое имя

image.Color color.Color
image.ColorModel color.Model
image.ColorModelFunc color.ModelFunc
image.PalettedColorModel color.Palette

image.RGBAColor color.RGBA
image.RGBA64Color color.RGBA64
image.NRGBAColor color.NRGBA
image.NRGBA64Color color.NRGBA64
image.AlphaColor color.Alpha
image.Alpha16Color color.Alpha16
image.GrayColor color.Gray
image.Gray16Color color.Gray16

image.RGBAColorModel color.RGBAModel
image.RGBA64ColorModel color.RGBA64Model
image.NRGBAColorModel color.NRGBAModel
image.NRGBA64ColorModel color.NRGBA64Model
image.AlphaColorModel color.AlphaModel
image.Alpha16ColorModel color.Alpha16Model
image.GrayColorModel color.GrayModel
image.Gray16ColorModel color.Gray16Model

ycbcr.RGBToYCbCr color.RGBToYCbCr
ycbcr.YCbCrToRGB color.YCbCrToRGB
ycbcr.YCbCrColorModel color.YCbCrModel
ycbcr.YCbCrColor color.YCbCr
ycbcr.YCbCr image.YCbCr

ycbcr.SubsampleRatio444 image.YCbCrSubsampleRatio444
ycbcr.SubsampleRatio422 image.YCbCrSubsampleRatio422
ycbcr.SubsampleRatio420 image.YCbCrSubsampleRatio420

image.ColorImage image.Uniform

Функции New пакета image (NewRGBA, NewRGBA64 и т. д.) принимают в качестве аргумента image.Rectangle вместо четырёх целых чисел.

Наконец, появились новые предопределённые переменные типа color.Color: color.Black, color.White, color.Opaque и color.Transparent.

Обновление: Запуск команды go fix обновит почти весь код, затронутый этими изменениями.

Пакет log/syslog

В Go 1 функция syslog.NewLogger возвращает ошибку, а также log.Logger.

Обновление: Минимальное количество затронутого кода будет замечено компилятором и должно быть обновлено вручную.

Пакет mime

В Go 1 функция FormatMediaType пакета mime была упрощена для согласования с ParseMediaType. Теперь она принимает "text/html" вместо "text" и "html".

Обновление: Минимальное количество затронутого кода будет замечено компилятором и должно быть обновлено вручную.

Пакет net

В Go 1 различные методы SetTimeout, SetReadTimeout и SetWriteTimeout были заменены на SetDeadline, SetReadDeadline и SetWriteDeadline соответственно. Вместо того, чтобы принимать значение таймаута в наносекундах, применяемое ко всей активности по соединению, новые методы устанавливают абсолютный дедлайн (в виде значения типа time.Time), после которого чтение и запись будут завершаться с ошибкой таймаута и больше не будут блокироваться.

Также появились новые функции: net.DialTimeout для упрощения таймаута при подключении к сетевому адресу и net.ListenMulticastUDP для возможности одновременного прослушивания multicast UDP через несколько слушателей. Функция net.ListenMulticastUDP заменяет старые методы JoinGroup и LeaveGroup.

Обновление: Код, использующий старые методы, не будет компилироваться и должен быть обновлён вручную. Семантическое изменение делает автоматическое обновление невозможным для инструмента fix.

Пакет os

Функция Time была удалена; вызывающий код должен использовать тип Time из пакета time.

Функция Exec была удалена; вызывающие программы должны использовать функцию Exec из пакета syscall, если она доступна.

Функция ShellExpand была переименована в ExpandEnv.

Функция NewFile теперь принимает uintptr fd вместо int. Метод Fd для файлов также теперь возвращает uintptr.

В пакете os больше не существует констант ошибок, таких как EINVAL, поскольку набор значений зависел от базовой операционной системы. Появились новые переносимые функции, например IsPermission, чтобы проверять общие свойства ошибок, а также несколько новых значений ошибок с более «Go-подобными» именами, таких как ErrPermission и ErrNotExist.

Функция Getenverror была удалена. Чтобы различать отсутствующую переменную окружения и пустую строку, следует использовать os.Environ или syscall.Getenv.

Метод Process.Wait больше не принимает аргумент опций, и связанные с ним константы были удалены из пакета. Также удалена функция Wait; остаётся только метод типа Process.

Тип Waitmsg, возвращаемый функцией Process.Wait, был заменён более переносимым типом ProcessState с методами доступа для получения информации о процессе. Благодаря изменениям в Wait, значение ProcessState всегда описывает завершившийся процесс. В целях повышения переносимости интерфейс был упрощён, но значения, возвращаемые методами ProcessState.Sys и ProcessState.SysUsage, можно преобразовать с помощью утверждения типа к специфичным для системы структурам данных, таким как syscall.WaitStatus и syscall.Rusage в Unix.

Обновление: Запуск команды go fix удалит нулевой аргумент у Process.Wait. Все остальные изменения будут замечены компилятором и должны быть обновлены вручную.

Тип os.FileInfo

В Go 1 тип os.FileInfo был переопределен, изменяя его от структуры к интерфейсу:

<code>    type FileInfo interface {
  Name() string       // базовое имя файла
  Size() int64        // длина в байтах
  Mode() FileMode     // биты режима файла
  ModTime() time.Time // время модификации
  IsDir() bool        // сокращение для Mode().IsDir()
  Sys() interface{}   // базовый источник данных (может возвращать nil)
}
</code>

Информация о режиме файла была перемещена в подтип под названием os.FileMode, простой целочисленный тип с методами IsDir, Perm и String.

Системно-зависимые детали режимов файлов и свойств, такие как (в Unix) i-номер, были полностью удалены из FileInfo. Вместо этого каждый операционной системой предоставляет реализацию интерфейса FileInfo в пакете os, который имеет метод Sys, возвращающий системно-зависимое представление метаданных файла. Например, чтобы узнать i-номер файла в Unix-системе, распакуйте FileInfo следующим образом:

<code>    fi, err := os.Stat("hello.go")
if err != nil {
  log.Fatal(err)
}
// Проверим, что это файл Unix.
unixStat, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
  log.Fatal("hello.go: не файл Unix")
}
fmt.Printf("i-номер файла: %d\n", unixStat.Ino)
</code>

Предполагая (что не очень разумно), что "hello.go" — файл Unix, выражение для получения i-номера можно сократить до

<code>    fi.Sys().(*syscall.Stat_t).Ino
</code>

Большинство применений FileInfo требуют только методов стандартного интерфейса.

Пакет os больше не содержит обёрток для POSIX-ошибок, таких как ENOENT. Для немногих программ, которым нужно проверять конкретные условия ошибок, теперь доступны логические функции IsExist, IsNotExist и IsPermission.

f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if os.IsExist(err) {
  log.Printf("%s уже существует", name)
}

Обновление: Запуск команды go fix обновит код, использующий старое эквивалентное текущему API os.FileInfo и os.FileMode. Код, который нуждается в системно-зависимых деталях файла, должен быть обновлён вручную. Код, использующий старые значения POSIX-ошибок из пакета os, не будет компилироваться и также потребует ручного обновления.

Пакет os/signal

Пакет os/signal в Go 1 заменяет функцию Incoming, которая возвращала канал, получавший все входящие сигналы, на функцию Notify, которая запрашивает доставку конкретных сигналов на существующий канал.

Обновление: Код должен быть обновлён вручную. Буквальный перевод

<code>c := signal.Incoming()
</code>

будет

<code>c := make(chan os.Signal, 1)
signal.Notify(c) // запросить все сигналы
</code>

но большинство кода должно явно указывать нужные сигналы для обработки:

<code>c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT)
</code>

Пакет path/filepath

В Go 1 функция Walk пакета path/filepath была изменена таким образом, что теперь она принимает значение функции типа WalkFunc вместо значения интерфейса Visitor. WalkFunc объединяет обработку как файлов, так и каталогов.

<code>    type WalkFunc func(path string, info os.FileInfo, err error) error
</code>

Функция WalkFunc будет вызываться даже для файлов или каталогов, которые не удалось открыть; в таких случаях аргумент ошибки будет описывать сбой. Если содержимое каталога должно быть пропущено, функция должна возвращать значение filepath.SkipDir

markFn := func(path string, info os.FileInfo, err error) error {
  if path == "pictures" { <span class="comment">// Will skip walking of directory pictures and its contents.</span>
  return filepath.SkipDir
}
if err != nil {
  return err
}
log.Println(path)
return nil
}
err := filepath.Walk(".", markFn)
if err != nil {
  log.Fatal(err)
}

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

Пакет regexp

Пакет regexp был переписан. Он имеет тот же интерфейс, но спецификация поддерживаемых регулярных выражений изменилась с формата «egrep» на формат RE2.

Обновление: Код, использующий пакет, должен быть проверен вручную на соответствие регулярных выражений.

Пакет runtime

В Go 1 значительная часть API, экспортируемого пакетом runtime, была удалена в пользу функциональности, предоставляемой другими пакетами. Код, использующий интерфейс runtime.Type или его конкретные реализации, теперь должен использовать пакет reflect. Код, использующий runtime.Semacquire или runtime.Semrelease, должен использовать каналы или абстракции из пакета sync. Функции runtime.Alloc, runtime.Free и runtime.Lookup, небезопасный API, созданный для отладки распределителя памяти, не имеют замены.

Ранее runtime.MemStats была глобальной переменной, содержащей статистику распределения памяти, и вызовы runtime.UpdateMemStats обеспечивали её актуальность. В Go 1 runtime.MemStats является типом структуры, и код должен использовать runtime.ReadMemStats для получения текущей статистики.

Пакет добавляет новую функцию, runtime.NumCPU, которая возвращает количество доступных для параллельного выполнения процессоров, сообщаемых ядром операционной системы. Её значение может быть использовано для настройки параметра GOMAXPROCS. Функции runtime.Cgocalls и runtime.Goroutines были переименованы в runtime.NumCgoCall и runtime.NumGoroutine.

Обновление: Запуск команды go fix обновит код с учётом переименованных функций. Другой код необходимо будет обновить вручную.

Пакет strconv

В Go 1 пакет strconv был существенно переработан, чтобы сделать его более похожим на Go и менее похожим на C, хотя Atoi остался (он аналогичен int(ParseInt(x, 10, 0)), как и Itoa(x) (FormatInt(int64(x), 10)). Также появились новые варианты некоторых функций, которые добавляют данные в срезы байт, а не возвращают строки, чтобы обеспечить контроль над выделением памяти.

В следующей таблице представлены переименования; полные детали можно найти в документации пакета.

Старый вызов Новый вызов

Atob(x) ParseBool(x)

Atof32(x) ParseFloat(x, 32)§
Atof64(x) ParseFloat(x, 64)
AtofN(x, n) ParseFloat(x, n)

Atoi(x) Atoi(x)
Atoi(x) ParseInt(x, 10, 0)§
Atoi64(x) ParseInt(x, 10, 64)

Atoui(x) ParseUint(x, 10, 0)§
Atoui64(x) ParseUint(x, 10, 64)

Btoi64(x, b) ParseInt(x, b, 64)
Btoui64(x, b) ParseUint(x, b, 64)

Btoa(x) FormatBool(x)

Ftoa32(x, f, p) FormatFloat(float64(x), f, p, 32)
Ftoa64(x, f, p) FormatFloat(x, f, p, 64)
FtoaN(x, f, p, n) FormatFloat(x, f, p, n)

Itoa(x) Itoa(x)
Itoa(x) FormatInt(int64(x), 10)
Itoa64(x) FormatInt(x, 10)

Itob(x, b) FormatInt(int64(x), b)
Itob64(x, b) FormatInt(x, b)

Uitoa(x) FormatUint(uint64(x), 10)
Uitoa64(x) FormatUint(x, 10)

Uitob(x, b) FormatUint(uint64(x), b)
Uitob64(x, b) FormatUint(x, b)

Обновление: Запуск go fix обновит почти весь код, затронутый изменениями.
§ Atoi сохраняется, но Atoui и Atof32 — нет, поэтому для них может потребоваться явное приведение типов, которое необходимо добавить вручную; инструмент go fix выдаст предупреждение об этом.

Пакеты шаблонов

Пакеты template и exp/template/html были перемещены в text/template и html/template. Более значительным является упрощение интерфейса этих пакетов. Язык шаблонов остался тем же, но концепция "набора шаблонов" исключена, а функции и методы пакетов были изменены соответственно, часто за счёт их удаления.

Вместо наборов объект Template может содержать несколько именованных определений шаблонов, по сути создавая пространства имён для вызова шаблонов. Шаблон может вызывать любой другой шаблон, связанный с ним, но только те, которые связаны с ним. Простейший способ связывания шаблонов — это их разбор вместе, что теперь стало проще благодаря новой структуре пакетов.

Обновление: Импорты будут обновлены с помощью инструмента fix. Использование одного шаблона останется в основном без изменений. Код, использующий несколько шаблонов одновременно, потребует ручного обновления. Примеры из документации пакета text/template могут служить руководством.

Пакет testing

Пакет testing имеет тип B, передаваемый как аргумент в функции бенчмарков. В Go 1 тип B получил новые методы, аналогичные методам типа T, позволяющие вести журнал и сообщать о сбоях.

func BenchmarkSprintf(b *testing.B) {
  <span class="comment">// Проверим корректность перед запуском бенчмарка.</span>
  b.StopTimer()
  got := fmt.Sprintf("%x", 23)
  const expect = "17"
  if expect != got {
    b.Fatalf("ожидалось %q; получено %q", expect, got)
  }
  b.StartTimer()
  for i := 0; i < b.N; i++ {
    fmt.Sprintf("%x", 23)
  }
}

Обновление: Существующий код остаётся неизменным, хотя бенчмарки, использующие println или panic, следует обновить, чтобы использовать новые методы.

Пакет testing/script

Пакет testing/script был удалён. Он был бесполезным.

Обновление: Вероятно, не затронет ни один код.

Пакет unsafe

В Go 1 были удалены функции unsafe.Typeof, unsafe.Reflect, unsafe.Unreflect, unsafe.New и unsafe.NewArray; они дублировали более безопасную функциональность, предоставленную пакетом reflect.

Обновление: Код, использующий эти функции, необходимо переписать с использованием пакета reflect. Изменения в encoding/gob и библиотеке protocol buffer могут быть полезны в качестве примеров.

Пакет url

В Go 1 несколько полей типа url.URL были удалены или заменены.

Метод String теперь предсказуемо перестраивает закодированную строку URL, используя все поля типа URL по мере необходимости. Результирующая строка больше не будет содержать экранированные пароли.

Поле Raw было удалено. В большинстве случаев метод String может быть использован вместо него.

Старое поле RawUserinfo заменено полем User типа *net.Userinfo. Значения этого типа могут быть созданы с помощью новых функций net.User и net.UserPassword. Функции EscapeUserinfo и UnescapeUserinfo также были удалены.

Поле RawAuthority было удалено. Та же самая информация доступна в полях Host и User.

Поле RawPath и метод EncodedPath были удалены. Информация о пути в URL с корневым путем (с косой чертой после схемы) теперь доступна только в декодированном виде в поле Path. Иногда требуется закодированные данные для получения информации, которая была потеряна в процессе декодирования. В таких случаях необходимо обращаться к исходным данным, из которых был построен URL.

URL с некорневыми путями, такими как "mailto:dev@golang.org?subject=Hi", также обрабатываются по-другому. Булево поле OpaquePath было удалено, а новое строковое поле Opaque было добавлено для хранения закодированного пути для таких URL. В Go 1 указанный URL парсится следующим образом:

<code>    URL{
  Scheme: "mailto",
  Opaque: "dev@golang.org",
  RawQuery: "subject=Hi",
}
</code>

В тип URL был добавлен новый метод RequestURI.

Функция ParseWithReference была переименована в ParseWithFragment.

Обновление: Код, использующий старые поля, не будет компилироваться и должен быть обновлён вручную. Семантические изменения делают невозможным автоматическое обновление с помощью инструмента.

Команда go

Go 1 представляет команду go — инструмент для получения, сборки и установки пакетов и команд Go. Команда go устраняет необходимость в makefile, вместо этого используя исходный код Go для поиска зависимостей и определения условий сборки. Большинство существующих программ на Go больше не будут требовать makefile для сборки.

См. Как писать код на Go для введения в команду go и документацию команды go для получения полной информации.

Обновление: Проекты, зависящие от старой системы сборки на основе makefile проекта Go (Make.pkg, Make.cmd и т. д.), должны перейти на использование команды go для сборки кода Go и, при необходимости, переписать свои makefile для выполнения дополнительных задач сборки.

Команда cgo

В Go 1 команда cgo использует другой файл _cgo_export.h, который генерируется для пакетов, содержащих строки с //export. Файл _cgo_export.h теперь начинается с комментария C preamble, чтобы определения экспортируемых функций могли использовать типы, определённые там. Это приводит к тому, что preamble компилируется несколько раз, поэтому пакет, использующий //export, не должен размещать определения функций или инициализации переменных в C preamble.

Упакованные релизы

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

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang