Gopls: Анализаторы

Gopls содержит драйвер для подключаемых, модульных статических анализаторов, таких как те, что используются в go vet.

Большинство анализаторов сообщают о ошибках в вашем коде; некоторые предлагают «быстрые исправления», которые могут быть применены непосредственно в вашем редакторе. Каждый раз при редактировании кода, gopls перезапускает свои анализаторы. Диагностика анализаторов помогает обнаруживать ошибки раньше, чем вы запустите тесты, или даже прежде чем сохраните файлы.

Этот документ описывает набор анализаторов, доступных в gopls, который объединяет анализаторы из различных источников:

  • все обычные анализаторы поиска ошибок из набора go vet (например, printf; см. go tool vet help для полного списка);
  • некоторые анализаторы с более значительными зависимостями, которые не могут быть использованы в go vet (например, nilness);
  • анализаторы, расширяющие ошибки компиляции, предлагая быстрые исправления распространённых ошибок (например, fillreturns); и
  • некоторые анализаторы, предлагающие возможные улучшения стиля (например, simplifyrange).

Чтобы включить или отключить анализаторы, используйте настройку analyses.

Кроме того, gopls включает набор staticcheck. Когда логическая настройка staticcheck не установлена, включено чуть более половины этих анализаторов по умолчанию; этот подмножество выбрано для точности и эффективности. Установите staticcheck в true, чтобы включить полный набор, или в false, чтобы отключить полный набор.

Анализаторы staticcheck, как и все остальные анализаторы, могут быть явно включены или отключены с помощью настройки конфигурации analyzers; эта настройка имеет приоритет над настройкой staticcheck, поэтому, независимо от значения staticcheck (true/false/unset), вы можете вносить корректировки в предпочитаемый набор анализаторов.

QF1001: Применить закон Де Моргана

Доступен с версии 2021.1

По умолчанию: выключен. Включите, установив "analyses": {"QF1001": true}.

Документация пакета: QF1001

QF1002: Преобразовать безметочный switch в меточный switch

Безметочный switch, который сравнивает одну переменную с рядом значений, может быть заменён меточным switch.

До:

<code>switch {
  case x == 1 || x == 2, x == 3:
    ...
    case x == 4:
      ...
      default:
        ...
      }
      </code>

После:

<code>switch x {
  case 1, 2, 3:
    ...
    case 4:
      ...
      default:
        ...
      }
      </code>

Доступен с версии 2021.1

По умолчанию: включён.

Документация пакета: QF1002

QF1003: Преобразовать цепочку if/else-if в меточный switch

Последовательность проверок if/else-if, сравнивающих одну и ту же переменную с значениями, может быть заменена меточным switch.

До:

<code>if x == 1 || x == 2 {
  ...
} else if x == 3 {
  ...
} else {
  ...
}
</code>

После:

<code>switch x {
  case 1, 2:
    ...
    case 3:
      ...
      default:
        ...
      }
      </code>

Доступно с 2021.1

По умолчанию: включено.

Документация пакета: QF1003

QF1004: Используйте strings.ReplaceAll вместо strings.Replace с n == -1

Доступно с 2021.1

По умолчанию: включено.

Документация пакета: QF1004

QF1005: Раскройте вызов math.Pow

Некоторые использования math.Pow можно упростить до базового умножения.

До:

<code>math.Pow(x, 2)
</code>

После:

<code>x * x
</code>

Доступно с 2021.1

По умолчанию: выключено. Включите, установив "analyses": {"QF1005": true}.

Документация пакета: QF1005

QF1006: Поднимите if+break в условие цикла

До:

<code>for {
  if done {
    break
  }
  ...
}
</code>

После:

<code>for !done {
  ...
}
</code>

Доступно с 2021.1

По умолчанию: выключено. Включите, установив "analyses": {"QF1006": true}.

Документация пакета: QF1006

QF1007: Объедините условное присваивание в объявление переменной

До:

<code>x := false
if someCondition {
  x = true
}
</code>

После:

<code>x := someCondition
</code>

Доступно с 2021.1

По умолчанию: выключено. Включите, установив "analyses": {"QF1007": true}.

Документация пакета: QF1007

QF1008: Исключите встроенные поля из выражения селектора

Доступно с 2021.1

По умолчанию: выключено. Включите, установив "analyses": {"QF1008": true}.

Документация пакета: QF1008

QF1009: Используйте time.Time.Equal вместо оператора ==

Доступно с 2021.1

По умолчанию: включено.

Документация пакета: QF1009

QF1010: Преобразуйте срез байтов в строку при печати

Доступно с 2021.1

По умолчанию: включено.

Документация пакета: QF1010

QF1011: Исключите избыточный тип из объявления переменной

Доступно с 2021.1

По умолчанию: выключено. Включите, установив "analyses": {"QF1011": true}.

Документация пакета: QF1011

QF1012: Используйте fmt.Fprintf(x, …) вместо x.Write(fmt.Sprintf(…))

Доступно с 2022.1

По умолчанию: включено.

Документация пакета: QF1012

S1000: Используйте простую отправку или получение из канала вместо select с единственным вариантом

Select-инструкции с единственным вариантом могут быть заменены на простую отправку или получение.

До:

<code>select {
  case x := <-ch:
    fmt.Println(x)
  }
  </code>

После:

<code>x := <-ch
fmt.Println(x)
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1000

S1001: Замените цикл for вызовом copy

Используйте copy() для копирования элементов из одного среза в другой. Для массивов одинакового размера можно использовать простое присваивание.

До:

<code>for i, x := range src {
  dst[i] = x
}
</code>

После:

<code>copy(dst, src)
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1001

S1002: Пропустите сравнение с булевской константой

До:

<code>if x == true {}
</code>

После:

<code>if x {}
</code>

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1002": true}.

Документация пакета: S1002

S1003: Замените вызов strings.Index на strings.Contains

До:

<code>if strings.Index(x, y) != -1 {}
</code>

После:

<code>if strings.Contains(x, y) {}
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1003

S1004: Замените вызов bytes.Compare на bytes.Equal

До:

<code>if bytes.Compare(x, y) == 0 {}
</code>

После:

<code>if bytes.Equal(x, y) {}
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1004

S1005: Уберите ненужное использование пустого идентификатора

Во многих случаях присваивание пустому идентификатору является лишним.

До:

<code>for _ = range s {}
x, _ = someMap[key]
_ = <-ch
</code>

После:

<code>for range s{}
x = someMap[key]
<-ch
</code>

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1005": true}.

Документация пакета: S1005

S1006: Используйте ‘for { … }’ для бесконечных циклов

Для бесконечных циклов использование for { … } является наиболее идиоматичным выбором.

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1006": true}.

Документация пакета: S1006

S1007: Упростите регулярное выражение, используя необработанный строковый литерал

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

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

До:

<code>regexp.Compile("\\A(\\w+) profile: total \\d+\\n\\z")
</code>

После:

<code>regexp.Compile(`\A(\w+) profile: total \d+\n\z`)
</code>

Доступно начиная с 2017.1

По умолчанию: включено.

Документация пакета: S1007

S1008: Упростить возвращаемое логическое выражение

До:

<code>if <expr> {
  return true
}
return false
</code>

После:

<code>return <expr>
</code>

Доступно начиная с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1008": true}.

Документация пакета: S1008

S1009: Пропустить избыточную проверку на nil для срезов, карт и каналов

Функция len определена для всех срезов, карт и каналов, даже для nil, которые имеют длину ноль. Не обязательно проверять на nil перед тем, как проверить, что их длина не равна нулю.

До:

<code>if x != nil && len(x) != 0 {}
</code>

После:

<code>if len(x) != 0 {}
</code>

Доступно начиная с 2017.1

По умолчанию: включено.

Документация пакета: S1009

S1010: Пропустить индекс среза по умолчанию

При нарезке второй индекс по умолчанию равен длине значения, что делает s[n:len(s)] и s[n:] эквивалентными.

Доступно начиная с 2017.1

По умолчанию: включено.

Документация пакета: S1010

S1011: Использовать один append для конкатенации двух срезов

До:

<code>for _, e := range y {
  x = append(x, e)
}
for i := range y {
  x = append(x, y[i])
}
for i := range y {
  v := y[i]
  x = append(x, v)
}
</code>

После:

<code>x = append(x, y...)
x = append(x, y...)
x = append(x, y...)
</code>

Доступно начиная с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1011": true}.

Документация пакета: S1011

S1012: Заменить time.Now().Sub(x) на time.Since(x)

Вспомогательная функция time.Since имеет тот же эффект, что и использование time.Now().Sub(x), но более проста для чтения.

До:

<code>time.Now().Sub(x)
</code>

После:

<code>time.Since(x)
</code>

Доступно начиная с 2017.1

По умолчанию: включено.

Документация пакета: S1012

S1016: Использовать преобразование типа вместо ручного копирования полей структуры

Две структуры с одинаковыми полями могут быть преобразованы друг в друга. В более ранних версиях Go поля должны были иметь идентичные теги структуры. Однако, начиная с Go 1.8, теги структуры игнорируются при преобразованиях. Таким образом, не требуется вручную копировать каждое поле отдельно.

До:

<code>var x T1
y := T2{
  Field1: x.Field1,
  Field2: x.Field2,
}
</code>

После:

<code>var x T1
y := T2(x)
</code>

Доступно начиная с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1016": true}.

Документация пакета: S1016

S1017: Замените ручную обрезку на strings.TrimPrefix

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

До:

<code>if strings.HasPrefix(str, prefix) {
  str = str[len(prefix):]
}
</code>

После:

<code>str = strings.TrimPrefix(str, prefix)
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1017

S1018: Используйте ‘copy’ для сдвига элементов

Функция copy() позволяет использовать один и тот же исходный и целевой срез, даже при перекрывающихся диапазонах. Это делает её идеальной для сдвига элементов в срезе.

До:

<code>for i := 0; i < n; i++ {
  bs[i] = bs[offset+i]
}
</code>

После:

<code>copy(bs[:n], bs[offset:])
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1018

S1019: Упростите вызов ‘make’, опустив избыточные аргументы

Функция ‘make’ имеет значения по умолчанию для аргументов длины и ёмкости. Для каналов длина по умолчанию равна нулю, а для срезов ёмкость по умолчанию равна длине.

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1019

S1020: Пропустите избыточную проверку на nil в утверждении типа

До:

<code>if _, ok := i.(T); ok && i != nil {}
</code>

После:

<code>if _, ok := i.(T); ok {}
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1020

S1021: Объедините объявление и присваивание переменной

До:

<code>var x uint
x = 1
</code>

После:

<code>var x uint = 1
</code>

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"S1021": true}.

Документация пакета: S1021

S1023: Пропустите избыточный контроль потока

Функции, которые не возвращают значение, не требуют инструкции return в качестве последней инструкции функции.

Операторы switch в Go не имеют автоматического перехода, в отличие от языков, таких как C. Нет необходимости использовать инструкцию break в качестве последней инструкции блока case.

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: S1023

S1024: Замените x.Sub(time.Now()) на time.Until(x)

Помощник time.Until имеет тот же эффект, что и использование x.Sub(time.Now()), но его легче читать.

До:

<code>x.Sub(time.Now())
</code>

После:

<code>time.Until(x)
</code>

Доступно с 2017.1

Значение по умолчанию: включено.

Документация пакета: S1024

S1025: Не используйте fmt.Sprintf("%s", x) без необходимости

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

Учитывая следующие общие определения

<code>type T1 string
type T2 int
func (T2) String() string { return "Hello, world" }
var x string
var y T1
var z T2
</code>

можно упростить

<code>fmt.Sprintf("%s", x)
fmt.Sprintf("%s", y)
fmt.Sprintf("%s", z)
</code>

до

<code>x
string(y)
z.String()
</code>

Доступно начиная с 2017.1

Значение по умолчанию: выключено. Включите, установив "analyses": {"S1025": true}.

Документация пакета: S1025

S1028: Упростите создание ошибок с помощью fmt.Errorf

До:

<code>errors.New(fmt.Sprintf(...))
</code>

После:

<code>fmt.Errorf(...)
</code>

Доступно начиная с 2017.1

Значение по умолчанию: включено.

Документация пакета: S1028

S1029: Итерируйтесь по строке напрямую

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

До:

<code>for _, r := range []rune(s) {}
</code>

После:

<code>for _, r := range s {}
</code>

Доступно начиная с 2017.1

Значение по умолчанию: выключено. Включите, установив "analyses": {"S1029": true}.

Документация пакета: S1029

S1030: Используйте bytes.Buffer.String или bytes.Buffer.Bytes

bytes.Buffer имеет как метод String, так и метод Bytes. Почти никогда не требуется использовать string(buf.Bytes()) или []byte(buf.String()) – просто используйте другой метод.

Единственное исключение — это операции поиска в карте. Благодаря оптимизации компилятора, m[string(buf.Bytes())] более эффективно, чем m[buf.String()].

Доступно начиная с 2017.1

Значение по умолчанию: включено.

Документация пакета: S1030

S1031: Исключите избыточную проверку на nil вокруг цикла

Можно использовать range на nil срезах и картах — цикл просто никогда не выполнится. Это делает дополнительную проверку на nil вокруг цикла избыточной.

До:

<code>if s != nil {
  for _, x := range s {
    ...
  }
}
</code>

После:

<code>for _, x := range s {
  ...
}
</code>

Доступно начиная с 2017.1

Значение по умолчанию: включено.

Документация пакета: S1031

S1032: Используйте sort.Ints(x), sort.Float64s(x) и sort.Strings(x)

Функции sort.Ints, sort.Float64s и sort.Strings легче читаются, чем sort.Sort(sort.IntSlice(x)), sort.Sort(sort.Float64Slice(x)) и sort.Sort(sort.StringSlice(x)).

До:

<code>sort.Sort(sort.StringSlice(x))
</code>

После:

<code>sort.Strings(x)
</code>

Доступен с 2019.1

По умолчанию: включено.

Документация пакета: S1032

S1033: Лишняя защита вокруг вызова ‘delete’

Вызов delete для nil карты является нетипичной операцией (no-op).

Доступен с 2019.2

По умолчанию: включено.

Документация пакета: S1033

S1034: Используйте результат утверждения типа для упрощения случаев

Доступен с 2019.2

По умолчанию: включено.

Документация пакета: S1034

S1035: Лишний вызов net/http.CanonicalHeaderKey в методе вызова на net/http.Header

Методы на net/http.Header, а именно Add, Del, Get и Set, уже нормализуют заданное имя заголовка.

Доступен с 2020.1

По умолчанию: включено.

Документация пакета: S1035

S1036: Лишняя защита вокруг доступа к карте

При доступе к ключу карты, который ещё не существует, вы получаете нулевое значение. Часто нулевое значение является подходящим значением, например, при использовании append или выполнении целочисленных вычислений.

Следующий код

<code>if _, ok := m["foo"]; ok {
  m["foo"] = append(m["foo"], "bar")
} else {
  m["foo"] = []string{"bar"}
}
</code>

можно упростить до

<code>m["foo"] = append(m["foo"], "bar")
</code>

и

<code>if _, ok := m2["k"]; ok {
  m2["k"] += 4
} else {
  m2["k"] = 4
}
</code>

можно упростить до

<code>m["k"] += 4
</code>

Доступен с 2020.1

По умолчанию: включено.

Документация пакета: S1036

S1037: Излично сложный способ сна

Использование инструкции select с единственным случаем получения из результата time.After является очень излишне сложным способом сна, который может быть намного проще выражено простым вызовом time.Sleep.

Доступен с 2020.1

По умолчанию: включено.

Документация пакета: S1037

S1038: Излишне сложный способ печати отформатированной строки

Вместо использования fmt.Print(fmt.Sprintf(…)) можно использовать fmt.Printf(…).

Доступен с 2020.1

По умолчанию: включено.

Документация пакета: S1038

S1039: Лишнее использование fmt.Sprint

Вызов fmt.Sprint с единственным строковым аргументом является избыточным и идентичен использованию строки напрямую.

Доступен с 2020.1

По умолчанию: включено.

Документация пакета: S1039

S1040: Утверждение типа к текущему типу

Утверждение типа x.(SomeInterface), когда x уже имеет тип SomeInterface, может завершиться неудачей только если x равен nil. Обычно, это оставшийся код, когда x имел другой тип, и вы можете безопасно удалить утверждение типа. Если вы хотите проверить, что x не равен nil, рассмотрите возможность явного использования сравнения if x == nil вместо того, чтобы полагаться на то, что утверждение типа вызовет панику.

Доступно с 2021.1

По умолчанию: включено.

Документация пакета: S1040

SA1000: Недопустимое регулярное выражение

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA1000": true}.

Документация пакета: SA1000

SA1001: Недопустимый шаблон

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA1001

SA1002: Недопустимый формат в time.Parse

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA1002": true}.

Документация пакета: SA1002

SA1003: Неподдерживаемый аргумент для функций в encoding/binary

Пакет encoding/binary может сериализовать только типы с известными размерами. Это исключает использование типов int и uint, поскольку их размеры различаются на разных архитектурах. Более того, он не поддерживает сериализацию карт, каналов, строк или функций.

До версии Go 1.8, bool также не поддерживался.

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA1003": true}.

Документация пакета: SA1003

SA1004: Подозрительно маленькое не типизированное значение в time.Sleep

Функция time.Sleep принимает time.Duration в качестве единственного аргумента. Длительности выражаются в наносекундах. Таким образом, вызов time.Sleep(1) приведет к сну на 1 наносекунду. Это является распространённым источником ошибок, так как функции сна в других языках часто принимают секунды или миллисекунды.

Пакет time предоставляет константы, такие как time.Second, чтобы выражать длительные периоды. Их можно комбинировать с арифметическими операциями для выражения произвольных длительностей, например 5 * time.Second для 5 секунд.

Если вы действительно хотите спать на очень короткое время, используйте n * time.Nanosecond, чтобы сообщить Staticcheck, что вы действительно хотели спать на некоторое количество наносекунд.

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA1004

SA1005: Недопустимый первый аргумент в exec.Command

os/exec запускает программы напрямую (используя варианты системных вызовов fork и exec в Unix-системах). Это не следует путать с запуском команды в оболочке. Оболочка позволяет использовать такие функции, как перенаправление ввода, каналы и общее скриптование. Оболочка также отвечает за разбиение пользовательского ввода на имя программы и её аргументы. Например, эквивалент

<code>ls / /tmp
</code>

будет

<code>exec.Command("ls", "/", "/tmp")
</code>

Если вы хотите запустить команду в оболочке, рассмотрите возможность использования чего-то вроде следующего – но имейте в виду, что не все системы, особенно Windows, будут иметь программу /bin/sh:

<code>exec.Command("/bin/sh", "-c", "ls | grep Awesome")
</code>

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA1005

SA1007: Неверный URL в net/url.Parse

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1007": true}.

Документация пакета: SA1007

SA1008: Неканонический ключ в карте http.Header

Ключи в картах http.Header являются каноническими, то есть следуют определённому сочетанию заглавных и строчных букв. Методы, такие как http.Header.Add и http.Header.Del, преобразуют входные данные в каноническую форму перед манипуляцией с картой.

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

<code>h := http.Header{}
h["etag"] = []string{"1234"}
h.Add("etag", "5678")
fmt.Println(h)
// Вывод:
// map[Etag:[5678] etag:[1234]]
</code>

Простой способ получения канонической формы ключа — использовать http.CanonicalHeaderKey.

Доступен с 2017.1

По умолчанию: включён.

Документация пакета: SA1008

SA1010: Вызов (*regexp.Regexp).FindAll с n == 0, что всегда приведёт к возврату нулевых результатов

Если n >= 0, функция возвращает не более n совпадений/подгрупп. Чтобы вернуть все результаты, следует указать отрицательное число.

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1010": true}.

Документация пакета: SA1010

SA1011: Различные методы пакета «strings» ожидают корректный UTF-8, но переданы некорректные данные

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1011": true}.

Документация пакета: SA1011

SA1012: Передаётся nil в функцию context.Context, рассмотрите возможность использования context.TODO

Доступен с 2017.1

По умолчанию: включён.

Документация пакета: SA1012

SA1013: Вызов io.Seeker.Seek с константой whence в качестве первого аргумента, но она должна быть вторым

Доступен с 2017.1

По умолчанию: включён.

Документация пакета: SA1013

SA1014: Передано непоказательное значение в Unmarshal или Decode

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1014": true}.

Документация пакета: SA1014

SA1015: Использование time.Tick таким образом, что приведёт к утечке. Рассмотрите использование time.NewTicker, и используйте time.Tick только в тестах, командах и бесконечных функциях

До Go 1.23 таймеры (time.Ticker) необходимо было закрывать, чтобы они могли быть собраны сборщиком мусора. Так как time.Tick не позволяет закрыть лежащий в основе таймер, его повторное использование приводило к утечке памяти.

В Go 1.23 это исправлено тем, что таймеры могут быть собраны даже если они не были закрыты.

Доступно с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA1015": true}.

Документация пакета: SA1015

SA1016: Перехват сигнала, который нельзя перехватить

Не все сигналы могут быть перехвачены процессом. В частности, в UNIX-подобных системах сигналы syscall.SIGKILL и syscall.SIGSTOP никогда не передаются процессу, а обрабатываются непосредственно ядром. Поэтому попытки обработки этих сигналов являются бессмысленными.

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA1016

SA1017: Каналы, используемые с os/signal.Notify, должны быть буферизованными

Пакет os/signal использует неблокирующие отправки в канал при доставке сигналов. Если принимающая сторона канала не готова и канал либо не буферизован, либо полон, сигнал будет потерян. Чтобы избежать пропуска сигналов, канал должен быть буферизованным и иметь соответствующий размер. Для канала, используемого для уведомления об одном значении сигнала, буфер размером 1 будет достаточным.

Доступно с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA1017": true}.

Документация пакета: SA1017

SA1018: Вызов strings.Replace с n == 0, что не приводит к замене

При n == 0 не будет заменено ни одной строки. Чтобы заменить все вхождения, следует использовать отрицательное число или функцию strings.ReplaceAll.

Доступно с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA1018": true}.

Документация пакета: SA1018

Доступно с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA1020": true}.

Документация пакета: SA1020

SA1021: Использование bytes.Equal для сравнения двух net.IP

Тип net.IP хранит IPv4 или IPv6 адрес в виде среза байтов. Однако длина среза для IPv4 адреса может быть либо 4, либо 16 байт, используя различные способы представления IPv4 адресов. Чтобы корректно сравнивать два значения net.IP, следует использовать метод net.IP.Equal, поскольку он учитывает оба представления.

Доступно с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA1021": true}.

Документация пакета: SA1021

SA1023: Изменение буфера в реализации io.Writer

Метод Write не должен изменять данные среза, даже временно.

Доступно с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA1023": true}.

Документация пакета: SA1023

Документация пакета: SA1023

SA1024: Строка cutset содержит повторяющиеся символы

Функции strings.TrimLeft и strings.TrimRight принимают cutset, а не префикс. Cutset рассматривается как набор символов, которые нужно удалить из строки. Например,

<code>strings.TrimLeft("42133word", "1234")
</code>

приведёт к строке “word” – любые символы, которые являются 1, 2, 3 или 4, будут удалены слева от строки.

Чтобы удалить одну строку из другой, следует использовать strings.TrimPrefix.

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1024": true}.

Документация пакета: SA1024

SA1025: Невозможно корректно использовать возвращаемое значение (*time.Timer).Reset

Доступен с 2019.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1025": true}.

Документация пакета: SA1025

SA1026: Невозможно сериализовать каналы или функции

Доступен с 2019.2

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1026": true}.

Документация пакета: SA1026

SA1027: Атомарный доступ к 64-битной переменной должен быть выровнен по 64 бита

На ARM, x86-32 и 32-битном MIPS вызывающий код отвечает за выравнивание 64-битных слов, доступ к которым осуществляется атомарно. Первое слово в переменной или в выделенной структуре, массиве или срезе можно считать выровненным по 64 бита.

Вы можете использовать инструмент structlayout для проверки выравнивания полей в структуре.

Доступен с 2019.2

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1027": true}.

Документация пакета: SA1027

SA1028: sort.Slice можно использовать только со срезами

Первый аргумент sort.Slice должен быть срезом.

Доступен с 2020.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1028": true}.

Документация пакета: SA1028

SA1029: Неподходящий ключ в вызове context.WithValue

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

Чтобы избежать аллокаций при присваивании к интерфейсу{}, ключи контекста часто имеют конкретный тип struct{}. Альтернативно, статический тип экспортируемых переменных ключей контекста должен быть указателем или интерфейсом.

Доступен с 2020.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1029": true}.

Документация пакета: SA1029

SA1030: Недопустимый аргумент в вызове функции strconv

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

Доступен с 2021.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1030": true}.

Документация пакета: SA1030

SA1031: Пересекающиеся байтовые срезы переданы кодировщику

В функции кодирования вида Encode(dst, src) было обнаружено, что dst и src ссылаются на одну и ту же память. Это может привести к перезаписи байтов src до их чтения, когда кодировщик записывает более одного байта на каждый байт src.

Доступен с 2024.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1031": true}.

Документация пакета: SA1031

SA1032: Неправильный порядок аргументов в errors.Is

Первым аргументом функции errors.Is является ошибка, которую мы имеем, а вторым — ошибка, против которой мы пытаемся произвести сопоставление. Например:

<code>if errors.Is(err, io.EOF) { ... }
</code>

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

<code>if errors.Is(io.EOF, err) { /* это неверно */ }
</code>

Доступен с 2024.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA1032": true}.

Документация пакета: SA1032

SA2001: Пустая критическая секция, возможно, вы хотели отложить разблокировку?

Пустые критические секции вида

<code>mu.Lock()
mu.Unlock()
</code>

очень часто являются опечаткой, и вместо этого, вероятно, имелось в виду:

<code>mu.Lock()
defer mu.Unlock()
</code>

Обратите внимание, что иногда пустые критические секции могут быть полезны, как форма сигнала для ожидания другой горутины. Часто существуют более простые способы достижения того же эффекта. Если это не так, код должен быть хорошо закомментирован, чтобы избежать путаницы. Сочетание таких комментариев с директивой //lint:ignore может использоваться для подавления этого редкого ложноположительного результата.

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA2001

SA2002: Вызов testing.T.FailNow или SkipNow в горутине, что не допускается

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA2002": true}.

Документация пакета: SA2002

SA2003: Отложенная блокировка сразу после блокировки, вероятно, имелось в виду отложить разблокировку

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA2003": true}.

Документация пакета: SA2003

SA3000: TestMain не вызывает os.Exit, скрывающий неудачи тестов

Исполняемые файлы тестов (и, соответственно, 'go test') завершаются с ненулевым кодом состояния, если какие-либо тесты завершились неудачей. При указании собственной функции TestMain, вы несете ответственность за обеспечение этого, вызвав os.Exit с правильным кодом. Правильный код возвращается (*testing.M).Run, поэтому обычный способ реализации TestMain заключается в завершении с помощью os.Exit(m.Run()).

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA3000

SA3001: Присваивание к b.N в бенчмарках искажает результаты

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

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA3001

SA4000: Бинарный оператор имеет одинаковые выражения по обе стороны

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA4000

SA4001: &*x упрощается до x, это не копирует x

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA4001

SA4003: Сравнение беззнаковых значений с отрицательными значениями бессмысленно

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA4003

SA4004: Цикл завершается неусловно после одной итерации

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA4004

SA4005: Присваивание поля, которое никогда не будет замечено. Вы имели в виду использовать указательный получатель?

Доступно с 2021.1

По умолчанию: выключено. Включите, установив "analyses": {"SA4005": true}.

Документация пакета: SA4005

SA4006: Значение, присвоенное переменной, никогда не читается до перезаписи. Забыли проверку ошибки или мертвый код?

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA4006": true}.

Документация пакета: SA4006

SA4008: Переменная в условии цикла никогда не изменяется, вы увеличиваете неправильную переменную?

Например:

<code>for i := 0; i < 10; j++ { ... }
</code>

Это также может происходить, когда цикл может выполниться только один раз из-за неусловного управления, которое завершает цикл. Например, когда тело цикла содержит неусловный break, return или panic:

<code>func f() {
  panic("oops")
}
func g() {
  for i := 0; i < 10; i++ {
    // f неусловно вызывает panic, что означает, что "i"
    // никогда не увеличивается.
    f()
  }
}
</code>

Доступно с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA4008": true}.

Документация пакета: SA4008

SA4009: Аргумент функции перезаписывается до первого использования

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA4009": true}.

Документация пакета: SA4009

SA4010: Результат вызова append никогда не будет замечен нигде

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA4010": true}.

Документация пакета: SA4010

SA4011: Оператор break не имеет эффекта. Возможно, вы хотели выйти из внешнего цикла?

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA4011

SA4012: Сравнение значения с NaN, хотя ни одно значение не равно NaN

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA4012": true}.

Документация пакета: SA4012

SA4013: Двойное отрицание булева значения (т.е. !!b) эквивалентно самому значению b. Это либо избыточно, либо опечатка.

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA4013

SA4014: Цепочка if/else if содержит повторяющиеся условия и отсутствуют побочные эффекты; если условие не совпадает в первый раз, оно не совпадет и во второй раз

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA4014

SA4015: Вызов функций, таких как math.Ceil, над float значениями, полученными из целых чисел, не имеет никакого полезного эффекта

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA4015": true}.

Документация пакета: SA4015

SA4016: Некоторые побитовые операции, такие как x ^ 0, не имеют никакого полезного эффекта

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA4016

SA4017: Отбрасывание возвращаемых значений функции без побочных эффектов делает вызов бессмысленным

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA4017": true}.

Документация пакета: SA4017

SA4018: Самоприсваивание переменных

Доступно с 2017.1

По умолчанию: выключено. Включается установкой "analyses": {"SA4018": true}.

Документация пакета: SA4018

SA4019: Несколько одинаковых build-ограничений в одном файле

Доступно с 2017.1

По умолчанию: включено.

Документация пакета: SA4019

SA4020: Недостижимая ветвь case в type switch

В type switch, подобном следующему

<code>type T struct{}
func (T) Read(b []byte) (int, error) { return 0, nil }
var v any = T{}
switch v.(type) {
  case io.Reader:
    // ...
    case T:
      // недостижимо
    }
    </code>

вторая ветвь case никогда не будет достигнута, потому что T реализует io.Reader и ветви case вычисляются в порядке их следования в исходном коде.

Еще один пример:

<code>type T struct{}
func (T) Read(b []byte) (int, error) { return 0, nil }
func (T) Close() error { return nil }
var v any = T{}
switch v.(type) {
  case io.Reader:
    // ...
    case io.ReadCloser:
      // недостижимо
    }
    </code>

Несмотря на то, что T имеет метод Close и, следовательно, реализует io.ReadCloser, io.Reader всегда будет совпадать первым. Набор методов io.Reader является подмножеством io.ReadCloser. Таким образом, невозможно совпасть со второй ветвью, не совпав с первой.

Структурно эквивалентные интерфейсы

Особый случай предыдущего примера — это структурно эквивалентные интерфейсы. Учитывая следующие объявления

<code>type T error
type V error
func doSomething() error {
  err, ok := doAnotherThing()
  if ok {
    return T(err)
  }
  return U(err)
}
</code>

следующий type switch будет иметь недостижимую ветвь case:

<code>switch doSomething().(type) {
  case T:
    // ...
    case V:
      // недостижимо
    }
    </code>

T всегда будет совпадать раньше, чем V, потому что они структурно эквивалентны и, следовательно, возвращаемое значение doSomething() реализует оба.

Доступно с 2019.2

По умолчанию: включено.

Документация пакета: SA4020

SA4022: Сравнение адреса переменной с nil

Код вроде ‘if &x == nil’ бессмыслен, потому что получение адреса переменной всегда даст непустой указатель.

Доступно с 2020.1

По умолчанию: включено.

Документация пакета: SA4022

SA4023: Невозможное сравнение значения интерфейса с не типизированным nil

Внутри интерфейсы реализуются как два элемента: тип T и значение V. V — это конкретное значение, например int, struct или указатель, никогда не интерфейс. Например, если мы сохраняем значение int 3 в интерфейсе, результат будет иметь схематично (T=int, V=3). Значение V также известно как динамическое значение интерфейса, поскольку переменная интерфейса может содержать разные значения V (и соответствующие типы T) во время выполнения программы.

Значение интерфейса равно nil, только если оба T и V не установлены, (T=nil, V не установлено). В частности, nil-интерфейс всегда содержит nil-тип. Если мы сохраняем nil-указатель типа *int внутри значения интерфейса, внутренний тип будет *int независимо от значения указателя: (T=*int, V=nil). Таким образом, такое значение интерфейса будет непустым даже тогда, когда значение указателя V внутри равно nil.

Эта ситуация может быть запутанной, и возникает, когда значение nil хранится внутри значения интерфейса, например, возвращаемого ошибки:

<code>func returnsError() error {
  var p *MyError = nil
  if bad() {
    p = ErrBad
  }
  return p // Will always return a non-nil error.
}
</code>

Если всё идёт хорошо, функция возвращает nil p, поэтому возвращаемое значение — это интерфейс ошибки, содержащий (T=*MyError, V=nil). Это означает, что если вызывающая сторона сравнивает возвращённую ошибку с nil, она всегда будет выглядеть так, как будто произошла ошибка, даже если ничего плохого не произошло. Чтобы вернуть корректную nil ошибку вызывающей стороне, функция должна явно возвращать nil:

<code>func returnsError() error {
  if bad() {
    return ErrBad
  }
  return nil
}
</code>

Хорошей практикой является использование типа error в сигнатуре функций, возвращающих ошибки (как было показано выше), а не конкретного типа, такого как *MyError, чтобы гарантировать правильное создание ошибки. Например, os.Open возвращает error, хотя, если он не равен nil, всегда имеет конкретный тип *os.PathError.

Аналогичные ситуации могут возникнуть при использовании интерфейсов. Просто помните, что если какое-либо конкретное значение было сохранено в интерфейсе, он не будет равен nil. Для получения дополнительной информации см. The Laws of Reflection.

Этот текст был скопирован с https://golang.org/doc/faq#nil_error, лицензированный под Creative Commons Attribution 3.0 License.

Доступен с версии 2020.2

По умолчанию: выключен. Включается установкой "analyses": {"SA4023": true}.

Документация пакета: SA4023

SA4024: Проверка невозможного возвращаемого значения из встроенной функции

Возвращаемые значения встроенных функций len и cap не могут быть отрицательными.

См. https://golang.org/pkg/builtin/#len и https://golang.org/pkg/builtin/#cap.

Пример:

<code>if len(slice) < 0 {
  fmt.Println("unreachable code")
}
</code>

Доступен с версии 2021.1

По умолчанию: включён.

Документация пакета: SA4024

SA4025: Целочисленное деление литералов, результат которого равен нулю

При делении двух целочисленных констант результат также будет целым числом. Таким образом, деление, например, 2 / 3 даёт 0. Это справедливо для всех следующих примеров:

<code>_ = 2 / 3
const _ = 2 / 3
const _ float64 = 2 / 3
_ = float64(2 / 3)
</code>

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

Доступен с версии 2021.1

По умолчанию: включён.

Документация пакета: SA4025

SA4026: Константы Go не могут выражать отрицательный ноль

В IEEE 754 арифметике с плавающей точкой ноль имеет знак и может быть положительным или отрицательным. Это может быть полезно в определённом численном коде.

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

Для явного и надежного создания отрицательного нуля можно использовать функцию math.Copysign: math.Copysign(0, -1).

Доступен с 2021.1

По умолчанию: включено.

Документация пакета: SA4026

SA4027: (*net/url.URL).Query возвращает копию, изменение которой не приводит к изменению URL

(*net/url.URL).Query анализирует текущее значение net/url.URL.RawQuery и возвращает его в виде карты типа net/url.Values. Последующие изменения этой карты не повлияют на URL, если только карта не будет закодирована и не будет присвоена URL.RawQuery.

В результате следующий шаблон кода является дорогостоящей операцией без эффекта: u.Query().Add(key, value).

Доступен с 2021.1

По умолчанию: включено.

Документация пакета: SA4027

SA4028: x % 1 всегда равно нулю

Доступен с 2022.1

По умолчанию: включено.

Документация пакета: SA4028

SA4029: Неэффективная попытка сортировки среза

sort.Float64Slice, sort.IntSlice и sort.StringSlice являются типами, а не функциями. Выполнение x = sort.StringSlice(x) не делает ничего, особенно не сортирует никаких значений. Правильное использование: sort.Sort(sort.StringSlice(x)) или sort.StringSlice(x).Sort(), но существуют более удобные вспомогательные функции, а именно sort.Float64s, sort.Ints и sort.Strings.

Доступен с 2022.1

По умолчанию: включено.

Документация пакета: SA4029

SA4030: Неэффективная попытка генерации случайного числа

Функции в пакете math/rand, которые принимают верхние пределы, такие как Intn, генерируют случайные числа в полузамкнутом интервале [0,n). Иными словами, сгенерированные числа будут >= 0 и < n – они не включают n. Следовательно, rand.Intn(1) не генерирует 0 или 1, он всегда генерирует 0.

Доступен с 2022.1

По умолчанию: включено.

Документация пакета: SA4030

SA4031: Проверка значения, которое никогда не будет равно nil, на равенство nil

Доступен с 2022.1

По умолчанию: выключено. Включите, установив "analyses": {"SA4031": true}.

Документация пакета: SA4031

SA4032: Сравнение runtime.GOOS или runtime.GOARCH с невозможным значением

Доступен с 2024.1

По умолчанию: включено.

Документация пакета: SA4032

SA5000: Присваивание nil карты

Доступен с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA5000": true}.

Документация пакета: SA5000

SA5001: Откладывание Close до проверки возможной ошибки

Доступен с 2017.1

По умолчанию: включено.

Документация пакета: SA5001

SA5002: Пустой цикл for {} выполняется в бесконечном цикле и может заблокировать планировщик

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA5002": true}.

Документация пакета: SA5002

SA5003: Операторы defer в бесконечных циклах никогда не выполнятся

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

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA5003

SA5004: Цикл for { select { … с пустой ветвью default выполняется в бесконечном цикле

Доступен с 2017.1

По умолчанию: включен.

Документация пакета: SA5004

SA5005: Финализатор ссылается на финализируемый объект, предотвращая сборку мусора

Финализатор — это функция, связанная с объектом, которая выполняется, когда сборщик мусора готов собрать данный объект, то есть когда объект больше не ссылается ни на что.

Если же финализатор ссылается на объект, он всегда будет оставаться последней ссылкой на этот объект, предотвращая сборщик мусора от его сборки. Финализатор никогда не выполнится, и объект никогда не будет собран, что приведёт к утечке памяти. По этой причине финализатор должен использовать свой первый аргумент для работы с объектом. Таким образом, количество ссылок может временно опуститься до нуля перед тем, как объект будет передан финализатору.

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA5005": true}.

Документация пакета: SA5005

SA5007: Бесконечный рекурсивный вызов

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

Эта проблема может возникнуть из-за простых ошибок, таких как забывание добавить условие выхода. Также это может происходить «намеренно». Некоторые языки имеют оптимизацию хвостовой рекурсии, которая делает некоторые бесконечные рекурсивные вызовы безопасными для использования. Однако Go не реализует TCO, поэтому вместо этого следует использовать цикл.

Доступен с 2017.1

По умолчанию: выключен. Включить можно, установив "analyses": {"SA5007": true}.

Документация пакета: SA5007

SA5008: Неверный тег структуры

Доступен с 2019.2

По умолчанию: включен.

Документация пакета: SA5008

SA5010: Невозможное утверждение типа

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

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

Эта проверка применяет ту же логику при утверждении одного интерфейса в другой. Если оба типа интерфейсов содержат один и тот же метод, но с разными сигнатурами, тогда утверждение типа также никогда не может завершиться успешно.

Доступна начиная с 2020.1

По умолчанию: выключена. Включить можно, установив "analyses": {"SA5010": true}.

Документация пакета: SA5010

SA5011: Возможное разыменование нулевого указателя

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

<code>func fn(x *int) {
  fmt.Println(*x)
  // Эта проверка на nil такая же важная, как и предыдущее разыменование
  if x != nil {
    foo(*x)
  }
}
func TestFoo(t *testing.T) {
  x := compute()
  if x == nil {
    t.Errorf("nil pointer received")
  }
  // t.Errorf не прерывает тест, поэтому если x равен nil, следующая строка вызовет панику.
  foo(*x)
}
</code>

Staticcheck пытается вывести, какие функции прерывают поток управления. Например, он осознаёт, что функция не продолжит выполнение после вызова panic или log.Fatal. Однако иногда эта проверка не срабатывает, особенно в присутствии условных операторов. Рассмотрим следующий пример:

<code>func Log(msg string, level int) {
  fmt.Println(msg)
  if level == levelFatal {
    os.Exit(1)
  }
}
func Fatal(msg string) {
  Log(msg, levelFatal)
}
func fn(x *int) {
  if x == nil {
    Fatal("unexpected nil pointer")
  }
  fmt.Println(*x)
}
</code>

Staticcheck пометит разыменование x, даже если оно абсолютно безопасно. Staticcheck не способен вывести, что вызов Fatal завершит выполнение программы. На данный момент самым простым решением является изменение определения функции Fatal следующим образом:

<code>func Fatal(msg string) {
  Log(msg, levelFatal)
  panic("unreachable")
}
</code>

Мы также жестко кодируем функции из популярных пакетов логирования, таких как logrus. Пожалуйста, создайте issue, если мы не поддерживаем популярный пакет.

Доступна начиная с 2020.1

По умолчанию: выключена. Включить можно, установив "analyses": {"SA5011": true}.

Документация пакета: SA5011

SA5012: Передача нечетного среза в функцию, ожидающую чётное количество элементов

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

Доступна начиная с 2020.2

По умолчанию: выключена. Включить можно, установив "analyses": {"SA5012": true}.

Документация пакета: SA5012

Доступна начиная с 2017.1

По умолчанию: выключена. Включить можно, установив "analyses": {"SA6000": true}.

Документация пакета: SA6000

SA6001: Пропущена возможность оптимизации при индексации карт с помощью срезов байтов

Ключи карт должны быть сравнимы, что исключает использование срезов байтов. Обычно это приводит к использованию строковых ключей и преобразованию срезов байтов в строки.

Обычно, преобразование среза байтов в строку требует копирования данных и приводит к выделению памяти. Однако компилятор распознаёт выражение m[string(b)] и использует данные из b напрямую, не копируя их, поскольку он знает, что данные не могут измениться во время поиска в карте. Это приводит к противоречивой ситуации, когда

<code>k := string(b)
println(m[k])
println(m[k])
</code>

будет менее эффективным, чем

<code>println(m[string(b)])
println(m[string(b)])
</code>

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

За историей этой оптимизации можно обратиться к коммиту f5f5a8b6209f84961687d993b93ea0d397f5d5bf в репозитории Go.

Доступно начиная с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA6001": true}.

Документация пакета: SA6001

SA6002: Хранение значений, не являющихся указателями, в sync.Pool, приводит к выделению памяти

sync.Pool используется для избежания ненужных выделений памяти и снижения нагрузки на сборщик мусора.

Когда передаётся значение, не являющееся указателем, в функцию, которая принимает интерфейс, значение должно быть размещено на куче, что означает дополнительное выделение памяти. Срезы — это частый кандидат для помещения в sync.Pool, и они представляют собой структуры с тремя полями (длина, ёмкость и указатель на массив). Чтобы избежать лишнего выделения памяти, следует хранить указатель на срез.

См. комментарии к https://go-review.googlesource.com/c/go/+/24371, где обсуждается эта проблема.

Доступно начиная с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA6002": true}.

Документация пакета: SA6002

SA6003: Преобразование строки в срез рун перед итерацией по ней

Может потребоваться итерация по рунам строки. Вместо преобразования строки в срез рун и последующей итерации по нему, можно итерироваться по самой строке. То есть,

<code>for _, r := range s {}
</code>

и

<code>for _, r := range []rune(s) {}
</code>

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

Обратите внимание, что если вам важны индексы, итерация по строке и по срезу рун даст разные индексы. Первая версия даёт смещения байтов, а вторая — индексы в срезе рун.

Доступно начиная с 2017.1

По умолчанию: выключено. Включить можно, установив "analyses": {"SA6003": true}.

Документация пакета: SA6003

SA6005: Неэффективное сравнение строк с использованием strings.ToLower или strings.ToUpper

Преобразование двух строк в один регистр и их последующее сравнение, как показано ниже,

<code>if strings.ToLower(s1) == strings.ToLower(s2) {
  ...
}
</code>

значительно дороже, чем сравнение их с помощью strings.EqualFold(s1, s2). Это связано как с использованием памяти, так и с вычислительной сложностью.

strings.ToLower должен выделить память для новых строк и полностью преобразовать обе строки, даже если они отличаются уже с первого байта. strings.EqualFold, напротив, сравнивает строки посимвольно. Он не создаёт две промежуточные строки и может завершиться, как только будет найден первый несовпадающий символ.

Для более подробного объяснения этой проблемы см. https://blog.digitalocean.com/how-to-efficiently-compare-strings-in-go/

Доступно начиная с 2019.2

По умолчанию: включено.

Документация пакета: SA6005

SA6006: Использование io.WriteString для записи []byte

Использование io.WriteString для записи среза байтов, как в

<code>io.WriteString(w, string(b))
</code>

является как ненужным, так и неэффективным. Преобразование из []byte в string вызывает выделение и копирование данных, и вместо этого можно просто использовать w.Write(b).

Доступно начиная с 2024.1

По умолчанию: включено.

Документация пакета: SA6006

SA9001: defer в циклах range может не выполниться в ожидаемое время

Доступно начиная с 2017.1

По умолчанию: выключено. Включите, установив "analyses": {"SA9001": true}.

Документация пакета: SA9001

SA9002: Использование не-восьмеричного os.FileMode, которое выглядит как будто оно должно быть восьмеричным.

Доступно начиная с 2017.1

По умолчанию: включено.

Документация пакета: SA9002

SA9003: Пустое тело в ветке if или else

Доступно начиная с 2017.1, не по умолчанию

По умолчанию: выключено. Включите, установив "analyses": {"SA9003": true}.

Документация пакета: SA9003

SA9004: Только первая константа имеет явный тип

В объявлении констант, таком как следующий:

<code>const (
  First byte = 1
  Second     = 2
)
</code>

константа Second не имеет того же типа, что и константа First. Этот конструктивный приём не следует путать с

<code>const (
  First byte = iota
  Second
)
</code>

где First и Second действительно имеют одинаковый тип. Тип передаётся только тогда, когда явное значение не присваивается константе.

При объявлении перечислений с явными значениями поэтому важно не писать

<code>const (
  EnumFirst EnumType = 1
  EnumSecond         = 2
  EnumThird          = 3
)
</code>

Разница в типах может вызвать различные запутанные поведения и ошибки.

Неправильный тип в объявлениях переменных

Наиболее очевидная проблема с такими некорректными перечислениями выражается в виде ошибки компиляции:

<code>package pkg
const (
  EnumFirst  uint8 = 1
  EnumSecond       = 2
)
func fn(useFirst bool) {
  x := EnumSecond
  if useFirst {
    x = EnumFirst
  }
}
</code>

не компилируется с ошибкой

<code>./const.go:11:5: cannot use EnumFirst (type uint8) as type int in assignment
</code>

Потеря наборов методов

Более тонкая проблема возникает с типами, имеющими методы и необязательные интерфейсы. Рассмотрим следующий пример:

<code>package main
import "fmt"
type Enum int
func (e Enum) String() string {
  return "an enum"
}
const (
  EnumFirst  Enum = 1
  EnumSecond      = 2
)
func main() {
  fmt.Println(EnumFirst)
  fmt.Println(EnumSecond)
}
</code>

Этот код выведет

<code>enum
2
</code>

поскольку EnumSecond не имеет явного типа, он по умолчанию принимает тип int.

Доступен с 2019.1

По умолчанию: включено.

Документация пакета: SA9004

SA9005: Попытка сериализовать структуру без публичных полей и без пользовательской сериализации

Пакеты encoding/json и encoding/xml работают только с экспортированными полями структур, а не с неэкспортированными. Обычно это ошибка, если попытаться (де)сериализовать структуры, состоящие только из неэкспортированных полей.

Эта проверка не будет отмечать вызовы типов, которые определяют пользовательское поведение сериализации, например, через методы MarshalJSON. Она также не будет отмечать пустые структуры.

Доступен с 2019.2

По умолчанию: выключено. Включите, установив "analyses": {"SA9005": true}.

Документация пакета: SA9005

SA9006: Подозрительный побитовый сдвиг целочисленного значения фиксированного размера

Побитовый сдвиг значения за пределы его размера всегда обнуляет значение.

Например:

<code>v := int8(42)
v >>= 8
</code>

всегда приведет к 0.

Эта проверка отмечает операции побитового сдвига только для целочисленных значений фиксированного размера. То есть int, uint и uintptr никогда не будут отмечены, чтобы избежать возможных ложных срабатываний в некоторых экзотических, но допустимых трюках с побитовой манипуляцией:

<code>// Очистка любого значения, превышающего 32 бита, если целые числа больше 32 бит.
func f(i int) int {
  v := i >> 32
  v = v << 32
  return i-v
}
</code>

Доступен с 2020.2

По умолчанию: включено.

Документация пакета: SA9006

SA9007: Удаление каталога, который не должен быть удален

Практически никогда не правильно удалять системные каталоги, такие как /tmp или домашний каталог пользователя. Однако легко сделать это по ошибке, например, случайно использовать os.TempDir вместо ioutil.TempDir, или забыть добавить суффикс к результату os.UserHomeDir.

Написание

<code>d := os.TempDir()
defer os.RemoveAll(d)
</code>

в ваших модульных тестах может иметь разрушительное влияние на стабильность вашей системы.

Эта проверка отмечает попытки удаления следующих каталогов:

Доступен с 2022.1

По умолчанию: выключено. Включите, установив "analyses": {"SA9007": true}.

Документация пакета: SA9007

SA9008: Блок else утверждения типа, вероятно, не читает правильное значение

При объявлении переменных как часть инструкции if (например, в 'if foo := …; foo {'), те же переменные будут доступны в области видимости блока else. Это означает, что в следующем примере

<code>if x, ok := x.(int); ok {
  // ...
} else {
  fmt.Printf("unexpected type %T", x)
}
</code>

переменная x в блоке else будет ссылаться на x из x, ok :=; она не будет ссылаться на x, который подвергается утверждению типа. Результат неудачного утверждения типа — это нулевое значение типа, к которому происходит утверждение, поэтому x в блоке else всегда будет иметь значение 0 и тип int.

Доступен с 2022.1

По умолчанию: выключено. Включите, установив "analyses": {"SA9008": true}.

Документация пакета: SA9008

SA9009: Недействительная директива компилятора Go

Была найдена потенциальная директива компилятора Go, но она не имеет эффекта, поскольку начинается с пробельных символов.

Доступна начиная с 2024.1

По умолчанию: включено.

Документация пакета: SA9009

ST1000: Некорректный или отсутствующий комментарий пакета

Пакеты должны иметь комментарий пакета, формат которого соответствует рекомендациям, описанным в https://go.dev/wiki/CodeReviewComments#package-comments.

Доступна начиная с 2019.1, не по умолчанию

По умолчанию: выключено. Включить можно установив "analyses": {"ST1000": true}.

Документация пакета: ST1000

ST1001: Точка импорта (dot import) не рекомендуется

Импорты с точкой, которые не находятся в внешних тестовых пакетах, не рекомендуются.

Опция dot_import_whitelist может использоваться для разрешения определённых импортов.

Цитата из руководства по коду Go Code Review Comments:

Форма импорта . может быть полезна в тестах, которые из-за циклических зависимостей не могут быть частью тестируемого пакета:

<code>package foo_test
import (
  "bar/testutil" // также импортирует "foo"
  . "foo"
)
</code>

В этом случае файл теста не может быть в пакете foo, потому что он использует bar/testutil, который импортирует foo. Поэтому мы используем форму import ., чтобы файл вел себя как часть пакета foo, даже если он не является такой. За исключением этого одного случая, не следует использовать import . в программах. Это делает программы гораздо труднее читать, поскольку непонятно, является ли имя, например Quux, идентификатором верхнего уровня в текущем пакете или в импортированном пакете.

Доступна начиная с 2019.1

Опции dot_import_whitelist

По умолчанию: выключено. Включить можно установив "analyses": {"ST1001": true}.

Документация пакета: ST1001

ST1003: Плохо выбранное имя идентификатора

Идентификаторы, такие как имена переменных и пакетов, следуют определённым правилам.

См. следующие ссылки для подробностей:

Доступна начиная с 2019.1, не по умолчанию

Опции initialisms

По умолчанию: выключено. Включить можно установив "analyses": {"ST1003": true}.

Документация пакета: ST1003

ST1005: Неправильно отформатированная строка ошибки

Строки ошибок следуют набору рекомендаций, чтобы обеспечить единообразие и хорошую компонуемость.

Цитата из руководства по коду Go Code Review Comments:

Строки ошибок не должны начинаться с заглавной буквы (если только они не начинаются с собственных имен или аббревиатур) или заканчиваться знаком препинания, поскольку они обычно печатаются после другого контекста. То есть используйте fmt.Errorf("something bad"), а не fmt.Errorf("Something bad"), чтобы log.Printf("Reading %s: %v", filename, err) форматировалось без лишней заглавной буквы в середине сообщения.

Доступно с 2019.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1005": true}.

Документация пакета: ST1005

ST1006: Плохо выбранное имя получателя

Цитата из комментариев по обзору кода на Go:

Имя получателя метода должно отражать его идентичность; часто достаточно аббревиатуры типа из одной или двух букв (например, «c» или «cl» для «Client»). Не используйте общие имена, такие как «me», «this» или «self», которые характерны для объектно-ориентированных языков и подчеркивают методы по сравнению с функциями. Имя не обязательно должно быть таким же описательным, как у аргумента метода, поскольку его роль очевидна и не выполняет документационной функции. Оно может быть очень коротким, поскольку будет появляться почти на каждой строке каждого метода типа; знакомство допускает краткость. Также следует быть последовательным: если вы называете получателя «c» в одном методе, не называйте его «cl» в другом.

Доступно с 2019.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1006": true}.

Документация пакета: ST1006

ST1008: Значение ошибки функции должно быть последним возвращаемым значением

Значение ошибки функции должно быть последним возвращаемым значением.

Доступно с 2019.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1008": true}.

Документация пакета: ST1008

ST1011: Плохо выбранное имя переменной типа time.Duration

Значения типа time.Duration представляют собой количество времени, которое выражается в количестве наносекунд. Выражение вроде 5 * time.Microsecond даёт значение 5000. Поэтому неуместно добавлять к переменной типа time.Duration суффикс единицы времени, такой как Msec или Milli.

Доступно с 2019.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1011": true}.

Документация пакета: ST1011

ST1012: Плохо выбранное имя переменной ошибки

Переменные ошибок, которые являются частью API, должны называться errFoo или ErrFoo.

Доступно с 2019.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1012": true}.

Документация пакета: ST1012

ST1013: Следует использовать константы для HTTP-кодов ошибок, а не магические числа

HTTP имеет огромное количество кодов состояния. Хотя некоторые из них хорошо известны (200, 400, 404, 500), большинство из них нет. Пакет net/http предоставляет константы для всех кодов состояния, входящих в различные спецификации. Рекомендуется использовать эти константы вместо жёстко закодированных магических чисел, чтобы значительно повысить читаемость кода.

Доступно с 2019.1

Параметры http_status_code_whitelist

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1013": true}.

Документация пакета: ST1013

ST1015: Случай по умолчанию в switch должен быть первым или последним

Доступно с 2019.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1015": true}.

Документация пакета: ST1015

ST1016: Используйте согласованные имена получателей методов

Доступно с 2019.1, не по умолчанию

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1016": true}.

Документация пакета: ST1016

ST1017: Не используйте Yoda-условия

Yoda-условия — это условия вида ‘if 42 == x’, где литерал находится слева от операции сравнения. Такая конструкция является распространённым идиоматическим приёмом в языках, где присваивание является выражением, чтобы избежать ошибок вроде ‘if (x = 42)’. В Go, где подобные ошибки невозможны, предпочтительнее более идиоматичная форма ‘if x == 42’.

Доступно с 2019.2

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1017": true}.

Документация пакета: ST1017

ST1018: Избегайте нулевой ширины и управляющих символов в строковых литералах

Доступно с 2019.2

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1018": true}.

Документация пакета: ST1018

ST1019: Импорт одного и того же пакета несколько раз

Go позволяет импортировать один и тот же пакет несколько раз, при условии, что используются различные псевдонимы импорта. То есть следующий фрагмент кода является корректным:

<code>import (
  "fmt"
  fumpt "fmt"
  format "fmt"
  _ "fmt"
)
</code>

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

Обратите внимание, что иногда эта функция может использоваться намеренно (см., например, https://github.com/golang/go/commit/3409ce39bfd7584523b7a8c150a310cea92d879d) – если вы хотите разрешить этот паттерн в вашем коде, рекомендуется отключить эту проверку.

Доступно с 2020.1

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1019": true}.

Документация пакета: ST1019

ST1020: Документация экспортируемой функции должна начинаться с имени функции

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

Если каждый комментарий к документации начинается с имени элемента, который он описывает, можно использовать подкоманду doc инструмента go и обработать вывод через grep.

См. https://go.dev/doc/effective_go#commentary для получения дополнительной информации о том, как писать хорошую документацию.

Доступно с 2020.1, не по умолчанию

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1020": true}.

Документация пакета: ST1020

ST1021: Документация экспортируемого типа должна начинаться с названия типа

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

Если каждый комментарий к документации начинается с названия элемента, который он описывает, вы можете использовать подкоманду doc инструмента go и передать вывод через grep.

Для получения дополнительной информации о том, как писать хорошую документацию, см. https://go.dev/doc/effective_go#commentary.

Доступен с версии 2020.1, не по умолчанию

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1021": true}.

Документация пакета: ST1021

ST1022: Документация экспортируемой переменной или константы должна начинаться с названия переменной

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

Если каждый комментарий к документации начинается с названия элемента, который он описывает, вы можете использовать подкоманду doc инструмента go и передать вывод через grep.

Для получения дополнительной информации о том, как писать хорошую документацию, см. https://go.dev/doc/effective_go#commentary.

Доступен с версии 2020.1, не по умолчанию

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1022": true}.

Документация пакета: ST1022

ST1023: Лишний тип в объявлении переменной

Доступен с версии 2021.1, не по умолчанию

По умолчанию: выключено. Включить можно, установив "analyses": {"ST1023": true}.

Документация пакета: ST1023

appends: проверка на отсутствие значений после append

Этот анализатор сообщает о вызовах append, которые не передают значения для добавления в срез.

<code>s := []string{"a", "b", "c"}
_ = append(s)
</code>

Такие вызовы всегда являются пустыми операциями и часто указывают на ошибку.

По умолчанию: включено.

Документация пакета: appends

asmdecl: отчет о несоответствиях между файлами ассемблера и объявлениями Go

По умолчанию: включено.

Документация пакета: asmdecl

assign: проверка на бесполезные присваивания

Этот анализатор сообщает о присваиваниях вида x = x или a[i] = a[i]. Эти операции почти всегда бесполезны, а даже если они не бесполезны, то, как правило, являются ошибкой.

По умолчанию: включено.

Документация пакета: assign

atomic: проверка на распространённые ошибки при использовании пакета sync/atomic

Анализатор атомарных операций ищет инструкции присваивания следующего вида:

<code>x = atomic.AddUint64(&x, 1)
</code>

которые не являются атомарными.

Значение по умолчанию: включено.

Документация пакета: atomic

atomicalign: проверка аргументов функций из sync/atomic на невыравненность по 64 битам

Значение по умолчанию: включено.

Документация пакета: atomicalign

bools: проверка на распространённые ошибки, связанные с булевыми операторами

Значение по умолчанию: включено.

Документация пакета: bools

buildtag: проверка директив //go:build и // +build

Значение по умолчанию: включено.

Документация пакета: buildtag

cgocall: обнаружение некоторых нарушений правил передачи указателей в cgo

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

Значение по умолчанию: включено.

Документация пакета: cgocall

composites: проверка на не ключевые составные литералы

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

Например,

<code>err = &net.DNSConfigError{err}
</code>

следует заменить на:

<code>err = &net.DNSConfigError{Err: err}
</code>

Значение по умолчанию: включено.

Документация пакета: composites

copylocks: проверка на неправильную передачу блокировок по значению

Случайное копирование значения, содержащего блокировку, такой как sync.Mutex или sync.WaitGroup, может привести к некорректной работе обеих копий. Обычно такие значения должны быть доступны через указатель.

Значение по умолчанию: включено.

Документация пакета: copylocks

deepequalerrors: проверка вызовов reflect.DeepEqual для значений ошибок

Анализатор deepequalerrors ищет вызовы следующего вида:

<code>reflect.DeepEqual(err1, err2)
</code>

где err1 и err2 — ошибки. Использование reflect.DeepEqual для сравнения ошибок не рекомендуется.

Значение по умолчанию: включено.

Документация пакета: deepequalerrors

defers: сообщать о распространённых ошибках в инструкциях defer

Анализатор defers выводит диагностическое сообщение, когда инструкция defer приведёт к вызову time.Since, который не будет отложен, поскольку опыт показывает, что это почти всегда ошибка.

Например:

<code>start := time.Now()
...
defer recordLatency(time.Since(start)) // error: call to time.Since is not deferred
</code>

Правильный код выглядит так:

<code>defer func() { recordLatency(time.Since(start)) }()
</code>

По умолчанию: включено.

Документация пакета: defers

deprecated: проверять использование устаревших идентификаторов

Анализатор deprecated ищет устаревшие символы и импорты пакетов.

См. https://go.dev/wiki/Deprecated, чтобы узнать о соглашении Go по документированию и обозначению устаревших идентификаторов.

По умолчанию: включено.

Документация пакета: deprecated

directive: проверять директивы инструментария Go, такие как //go:debug

Этот анализатор проверяет проблемы с известными директивами инструментария Go во всех исходных файлах Go в каталоге пакета, включая те, которые исключены с помощью ограничений //go:build, а также все не-Go исходные файлы.

Для //go:debug (см. https://go.dev/doc/godebug), анализатор проверяет, что директивы размещены только в файлах Go, только выше комментария пакета, и только в пакете main или в файлах *_test.go.

Поддержка других известных директив может быть добавлена в будущем.

Этот анализатор не проверяет //go:build, который обрабатывается анализатором buildtag.

По умолчанию: включено.

Документация пакета: directive

embed: проверять использование директивы //go:embed

Этот анализатор проверяет, что пакет embed импортирован, если присутствуют директивы //go:embed, предлагая исправление для добавления импорта, если он отсутствует.

Этот анализатор также проверяет, что директивы //go:embed предшествуют объявлению одной переменной.

По умолчанию: включено.

Документация пакета: embed

errorsas: сообщать о передаче неуказателей или неошибочных значений в errors.As

Анализ errorsas сообщает о вызовах errors.As, где тип второго аргумента не является указателем на тип, реализующий error.

По умолчанию: включено.

Документация пакета: errorsas

fillreturns: предлагать исправления для ошибок, связанных с некорректным количеством возвращаемых значений

Этот проверяющий инструмент предлагает исправления для ошибок типа «неправильное количество возвращаемых значений (ожидалось %d, получено %d)». Например:

<code>func m() (int, string, *bool, error) {
  return
}
</code>

превратится в

<code>func m() (int, string, *bool, error) {
  return 0, "", nil, nil
}
</code>

Эта функциональность аналогична https://github.com/sqs/goreturns.

По умолчанию: включено.

Документация пакета: fillreturns

framepointer: сообщать о сборке, которая портит указатель фрейма до его сохранения

По умолчанию: включено.

Документация пакета: framepointer

gofix: применять исправления на основе директив комментариев go:fix

Анализатор gofix встраивает функции и константы, помеченные для встраивания.

Функции

Для функции, помеченной для встраивания, например:

<code>//go:fix inline
func Square(x int) int { return Pow(x, 2) }
</code>

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

Встраивание может быть использовано для перехода от устаревшей функции:

<code>// Deprecated: prefer Pow(x, 2).
//go:fix inline
func Square(x int) int { return Pow(x, 2) }
</code>

Также может использоваться для перехода от устаревшего пакета, когда путь импорта изменился или доступна более новая версия пакета:

<code>package pkg
import pkg2 "pkg/v2"
//go:fix inline
func F() { pkg2.F(nil) }
</code>

Замена вызова pkg.F() на pkg2.F(nil) может не повлиять на работу программы, поэтому этот механизм предоставляет безопасный способ обновления большого количества вызовов. Мы рекомендуем, где это возможно, выражать старый API через новый, чтобы обеспечить автоматическую миграцию.

Инлайнер заботится о том, чтобы избежать изменений поведения, даже незначительных, таких как изменение порядка вычисления выражений аргументов. Если он не может безопасно исключить все переменные параметров, он может ввести «объявление привязки» следующего вида:

<code>var params = args
</code>

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

(В случаях, когда не безопасно «сократить» вызов — то есть заменить вызов f(x) телом функции f, подходящим образом подставленным — механизм инлайнера способен заменить f на литерал функции, func(){…}(). Однако анализатор gofix безусловно отбрасывает все такие «литерализации», опять же по причинам стиля.)

Константы

Для константы, помеченной для встраивания, например:

<code>//go:fix inline
const Ptr = Pointer
</code>

этот анализатор будет рекомендовать заменить использование Ptr на Pointer.

Как и с функциями, встраивание может использоваться для замены устаревших констант и констант в устаревших пакетах.

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

Комментарий “//go:fix inline” должен находиться перед единственным объявлением const, как показано выше; перед объявлением const, входящим в группу, как в этом примере:

<code>const (
  C = 1
  //go:fix inline
  Ptr = Pointer
)
</code>

или перед группой, применяющейся ко всем константам в группе:

<code>//go:fix inline
const (
  Ptr = Pointer
  Val = Value
)
</code>

Предложение https://go.dev/issue/32816 вводит директивы “//go:fix”.

Вы можете использовать эту (официально неподдерживаемую) команду для массового применения исправлений gofix:

<code>$ go run golang.org/x/tools/internal/gofix/cmd/gofix@latest -test ./...
</code>

(Не используйте «go get -tool» для добавления gopls в качестве зависимости вашего модуля; команды gopls должны собираться из их ветки релиза.)

По умолчанию: включено.

Документация пакета: gofix

hostport: проверка формата адресов, передаваемых в net.Dial

Этот анализатор отмечает код, который формирует строки сетевых адресов с помощью fmt.Sprintf, как в следующем примере:

<code>addr := fmt.Sprintf("%s:%d", host, 12345) // "will not work with IPv6"
...
conn, err := net.Dial("tcp", addr)       // "when passed to dial here"
</code>

Анализатор предлагает исправление, используя правильный подход — вызов net.JoinHostPort:

<code>addr := net.JoinHostPort(host, "12345")
...
conn, err := net.Dial("tcp", addr)
</code>

Аналогичное диагностическое сообщение и исправление создаются для форматной строки «%s:%s».

По умолчанию: включено.

Документация пакета: hostport

httpresponse: проверка ошибок при работе с HTTP-ответами

Частая ошибка при использовании пакета net/http — это откладывание вызова функции для закрытия тела http.Response Body до проверки ошибки, определяющей, является ли ответ допустимым:

<code>resp, err := http.Head(url)
defer resp.Body.Close()
if err != nil {
  log.Fatal(err)
}
// (defer statement belongs here)
</code>

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

По умолчанию: включено.

Документация пакета: httpresponse

ifaceassert: обнаружение невозможных утверждений типа интерфейс-к-интерфейсу

Этот проверяющий инструмент отмечает утверждения типа v.(T) и соответствующие случаи type-switch, в которых статический тип V переменной v является интерфейсом, который не может реализовать целевой интерфейс T. Это происходит, когда V и T содержат методы с одинаковыми именами, но разными сигнатурами. Пример:

<code>var v interface {
  Read()
}
_ = v.(io.Reader)
</code>

Метод Read в v имеет другую сигнатуру, чем метод Read в io.Reader, поэтому это утверждение не может быть успешным.

По умолчанию: включено.

Документация пакета: ifaceassert

infertypeargs: проверка на ненужные аргументы типа в выражениях вызова

Явные аргументы типа могут быть опущены из выражений вызова, если они могут быть выведены из аргументов функции или других аргументов типа:

<code>func f[T any](T) {}
func _() {
  f[string]("foo") // string could be inferred
}
</code>

По умолчанию: включено.

Документация пакета: infertypeargs

loopclosure: проверка ссылок на переменные цикла внутри вложенных функций

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

Примечание: Переменная цикла может жить дольше итерации цикла только в версиях Go <=1.21. В Go 1.22 и более поздних версиях время жизни переменных цикла изменилось таким образом, что создаётся новая переменная итерации на каждую итерацию цикла. (См. go.dev/issue/60078.)

В этом примере все отложенные функции выполняются после завершения цикла, поэтому все наблюдают финальное значение v [<go1.22].

<code>for _, v := range list {
  defer func() {
    use(v) // неверно
  }()
}
</code>

Одним из способов исправления является создание новой переменной для каждой итерации цикла:

<code>for _, v := range list {
  v := v // новая переменная на каждой итерации
  defer func() {
    use(v) // правильно
  }()
}
</code>

После версии Go 1.22, предыдущие два цикла эквивалентны и оба корректны.

Следующий пример использует оператор go и имеет аналогичную проблему [<go1.22]. Кроме того, он содержит гонку данных, потому что цикл обновляет v одновременно с горутинами, обращающимися к нему.

<code>for _, v := range elem {
  go func() {
    use(v)  // неверно, и есть гонка данных
  }()
}
</code>

Исправление такое же, как и раньше. Анализатор также сообщает о проблемах в горутинах, запущенных с помощью golang.org/x/sync/errgroup.Group. Сложно заметная вариация этого вида часто встречается в параллельных тестах:

<code>func Test(t *testing.T) {
  for _, test := range tests {
    t.Run(test.name, func(t *testing.T) {
      t.Parallel()
      use(test) // неверно, и есть гонка данных
    })
  }
}
</code>

Вызов t.Parallel() заставляет остальную часть функции выполняться одновременно с циклом [<go1.22].

Анализатор сообщает только о ссылках в последней инструкции, так как он недостаточно глубок, чтобы понять эффекты последующих инструкций, которые могут сделать ссылку безвредной. («Последняя инструкция» определяется рекурсивно в составных инструкциях, таких как if, switch и select.)

См.: https://golang.org/doc/go_faq.html#closures_and_goroutines

По умолчанию: включено.

Документация пакета: loopclosure

lostcancel: проверяет, что функция отмены, возвращённая context.WithCancel, вызывается

Функция отмены, возвращённая context.WithCancel, WithTimeout, WithDeadline и их вариациями, такие как WithCancelCause, должна быть вызвана, или новый контекст останется активным до тех пор, пока не будет отменён его родительский контекст. (Фоновый контекст никогда не отменяется.)

По умолчанию: включено.

Документация пакета: lostcancel

maprange: проверяет на ненужные вызовы maps.Keys и maps.Values в инструкциях range

Рассмотрим цикл, написанный следующим образом:

<code>for val := range maps.Values(m) {
  fmt.Println(val)
}
</code>

Такой цикл следует переписать без вызова maps.Values:

<code>for _, val := range m {
  fmt.Println(val)
}
</code>

golang.org/x/exp/maps возвращает срезы для Keys/Values вместо итераторов, но ненужные вызовы также следует удалять:

<code>for _, key := range maps.Keys(m) {
  fmt.Println(key)
}
</code>

следует переписать как:

<code>for key := range m {
  fmt.Println(key)
}
</code>

По умолчанию: включено.

Документация пакета: maprange

modernize: упрощает код с использованием современных конструкций

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

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

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

<code>$ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./...
</code>

(Не используйте «go get -tool» для добавления gopls в качестве зависимости вашего модуля; команды gopls необходимо собирать из их ветки релизов.)

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

Изменения, созданные этим инструментом, должны быть просмотрены обычным образом перед слиянием. В некоторых случаях цикл может быть заменён простым вызовом функции, что приведёт к потере комментариев внутри цикла. Человеческое суждение может потребоваться, чтобы избежать потери ценных комментариев.

Каждая диагностика, сообщаемая модернизатором, имеет определённую категорию. (Категории перечислены ниже.) Диагностики в некоторых категориях, таких как «efaceany» (которая заменяет «interface{}» на «any», когда это безопасно), особенно многочисленны. Упростить процесс проверки кода может применение исправлений в два прохода: первый проход включает только исправления категории «efaceany», второй — все остальные. Это можно реализовать с помощью флага -category:

<code>$ modernize -category=efaceany  -fix -test ./...
$ modernize -category=-efaceany -fix -test ./...
</code>

Категории диагностики modernize:

По умолчанию: включено.

Документация пакета: modernize

nilfunc: проверка на бессмысленные сравнения функций с nil

Бессмысленным сравнением считается выражение вроде f == nil по сравнению с f() == nil.

По умолчанию: включено.

Документация пакета: nilfunc

nilness: проверка на избыточные или невозможные nil-сравнения

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

<code>if r := recover(); r != nil {
  </code>

Эта проверка сообщает о следующих условиях:

<code>if f == nil { // невозможное условие (f — функция)
}
</code>

и:

<code>p := &v
...
if p != nil { // тавтология
}
</code>

и:

<code>if p == nil {
  print(*p) // разыменование nil
}
</code>

и:

<code>if p == nil {
  panic(p)
}
</code>

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

<code>...
err := g.Wait()
if err != nil {
  return err
}
partialSuccess := false
for _, err := range errs {
  if err == nil {
    partialSuccess = true
    break
  }
}
if partialSuccess {
  reportStatus(StatusMessage{
    Code:   code.ERROR,
    Detail: err.Error(), // "nil dereference in dynamic method call"
  })
  return nil
}
</code>

По умолчанию: включено.

Документация пакета: nilness

nonewvars: предложенные исправления для ошибок типа "нет новых переменных слева от :="

Этот проверяющий инструмент предлагает исправления для ошибок типа "нет новых переменных слева от :=". Например:

<code>z := 1
z := 2
</code>

превратится в

<code>z := 1
z = 2
</code>

По умолчанию: включено.

Документация пакета: nonewvars

noresultvalues: предложенные исправления для неожидаемых возвращаемых значений

Этот проверяющий инструмент предлагает исправления для ошибок типа "ожидаются нулевые возвращаемые значения" или "слишком много возвращаемых значений". Например:

<code>func z() { return nil }
</code>

превратится в

<code>func z() { return }
</code>

По умолчанию: включено.

Документация пакета: noresultvalues

printf: проверка согласованности строк форматирования Printf и аргументов

Проверка применяется к вызовам функций форматирования, таким как [fmt.Printf] и [fmt.Sprintf], а также к любым обнаруженным обёрткам этих функций, таким как [log.Printf]. Она сообщает о различных ошибках, таких как синтаксические ошибки в строке формата и несоответствия (по количеству и типу) между спецификаторами и их аргументами.

См. документацию пакета fmt для полного набора операторов формата и их типов операндов.

По умолчанию: включено.

Документация пакета: printf

recursiveiter: проверяет на неэффективные рекурсивные итераторы

Этот анализатор сообщает о случаях, когда функция, возвращающая итератор (iter.Seq или iter.Seq2), вызывает саму себя в качестве операнда инструкции range, поскольку это неэффективно.

При реализации итератора (например, iter.Seq[T]) для рекурсивного типа данных, такого как дерево или связный список, соблазнительно рекурсивно перебирать итератор для каждого дочернего элемента.

Вот пример наивного итератора по бинарному дереву:

<code>type tree struct {
  value       int
  left, right *tree
}
func (t *tree) All() iter.Seq[int] {
  return func(yield func(int) bool) {
    if t != nil {
      for elem := range t.left.All() { // "inefficient recursive iterator"
      if !yield(elem) {
        return
      }
    }
    if !yield(t.value) {
      return
    }
    for elem := range t.right.All() { // "inefficient recursive iterator"
    if !yield(elem) {
      return
    }
  }
}
}
}
</code>

Хотя он корректно перечисляет элементы дерева, он скрывает существенную проблему производительности — две, на самом деле. Рассмотрим сбалансированное дерево из N узлов. Итерация корневого узла приведет к вызову All для каждого узла дерева. Это приводит к цепочке вложенных активных инструкций range-over-func при вызове yield(t.value) на листовом узле.

Первая проблема производительности заключается в том, что каждая инструкция range-over-func обычно выделяет переменную в куче, поэтому итерация дерева выделяет столько переменных, сколько элементов в дереве, итого O(N) выделений, все из которых являются избыточными.

Вторая проблема заключается в том, что каждый вызов yield для листа дерева заставляет каждый из внешних циклов range получать значение, которое они затем немедленно передают своей соответствующей функции yield. Это приводит к цепочке из log(N) динамических вызовов yield на элемент, в сумме O(N*log N) динамических вызовов, тогда как необходимо лишь O(N).

Более эффективная стратегия реализации рекурсивных итераторов — сначала определить оператор "every" для вашего рекурсивного типа данных, где every(f) сообщает, является ли f(x) истинным для каждого элемента x в типе данных. Для нашего дерева функция every будет следующей:

<code>func (t *tree) every(f func(int) bool) bool {
  return t == nil ||
  t.left.every(f) && f(t.value) && t.right.every(f)
}
</code>

Затем итератор может быть просто выражен как тривиальная обёртка вокруг этой функции:

<code>func (t *tree) All() iter.Seq[int] {
  return func(yield func(int) bool) {
    _ = t.every(yield)
  }
}
</code>

По сути, tree.All вычисляет, возвращает ли yield true для каждого элемента, сокращая вычисление, если возвращается false, а затем отбрасывает финальный логический результат.

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

По умолчанию: включено.

Документация пакета: recursiveiter

shadow: проверяет на возможное непреднамеренное затенение переменных

Этот анализатор проверяет на затенённые переменные. Переменная, затенённая (shadowed), — это переменная, объявленная в внутренней области видимости с тем же именем и типом, что и переменная во внешней области видимости, и где внешняя переменная упоминается после объявления внутренней.

(Это определение может быть уточнено; модуль создаёт слишком много ложноположительных результатов и пока не включён по умолчанию.)

Например:

<code>func BadRead(f *os.File, buf []byte) error {
  var err error
  for {
    n, err := f.Read(buf) // скрывает переменную функции 'err'
    if err != nil {
      break // приводит к возврату неверного значения
    }
    foo(buf)
  }
  return err
}
</code>

По умолчанию: выключено. Включить можно, установив "analyses": {"shadow": true}.

Документация пакета: shadow

shift: проверка сдвигов, равных или превышающих ширину целого числа

По умолчанию: включено.

Документация пакета: shift

sigchanyzer: проверка на не буферизованные каналы типа os.Signal

Этот анализатор отмечает вызовы функции вида

<code>signal.Notify(c <-chan os.Signal, sig ...os.Signal),
</code>

где c — не буферизованный канал, что может привести к потере сигнала.

По умолчанию: включено.

Документация пакета: sigchanyzer

simplifycompositelit: проверка упрощений составных литералов

Составной литерал массива, среза или карты вида:

<code>[]T{T{}, T{}}
</code>

будет упрощён до:

<code>[]T{{}, {}}
</code>

Это одна из оптимизаций, которые применяются командой “gofmt -s”.

Анализатор игнорирует сгенерированный код.

По умолчанию: включено.

Документация пакета: simplifycompositelit

simplifyrange: проверка упрощений инструкций range

Цикл вида:

<code>for x, _ = range v {...}
</code>

будет упрощён до:

<code>for x = range v {...}
</code>

Цикл вида:

<code>for _ = range v {...}
</code>

будет упрощён до:

<code>for range v {...}
</code>

Это одна из оптимизаций, которые применяются командой “gofmt -s”.

Анализатор игнорирует сгенерированный код.

По умолчанию: включено.

Документация пакета: simplifyrange

simplifyslice: проверка упрощений срезов

Выражение среза вида:

<code>s[a:len(s)]
</code>

будет упрощено до:

<code>s[a:]
</code>

Это одна из оптимизаций, которые применяются командой “gofmt -s”.

Анализатор игнорирует сгенерированный код.

По умолчанию: включено.

Документация пакета: simplifyslice

slog: проверка некорректных вызовов структурированного логирования

Анализатор slog ищет вызовы функций из пакета log/slog, которые принимают чередующиеся пары ключ-значение. Он отмечает вызовы, где аргумент в позиции ключа не является строкой или slog.Attr, а также отмечает отсутствие значения у последнего ключа. Например, он отмечает

<code>slog.Warn("message", 11, "k") // аргумент "11" функции slog.Warn должен быть строкой или slog.Attr
</code>

и

<code>slog.Info("message", "k1", v1, "k2") // вызов slog.Info пропускает конечное значение
</code>

По умолчанию: включено.

Документация пакета: slog

sortslice: проверка типа аргумента функции sort.Slice

Функция sort.Slice требует аргумент типа среза. Проверяется, что значение типа interface{}, переданное в sort.Slice, действительно является срезом.

По умолчанию: включено.

Документация пакета: sortslice

stdmethods: проверка сигнатуры методов well-known интерфейсов

Иногда тип может быть предназначен для реализации интерфейса, но не удается это сделать из-за ошибки в сигнатуре метода. Например, результат метода WriteTo должен быть (int64, error), а не error, чтобы удовлетворить интерфейсу io.WriterTo:

<code>type myWriterTo struct{...}
func (myWriterTo) WriteTo(w io.Writer) error { ... }
</code>

Эта проверка гарантирует, что каждый метод, имя которого совпадает с одним из нескольких well-known методов интерфейсов стандартной библиотеки, имеет правильную сигнатуру для этого интерфейса.

Проверяемые имена методов включают:

<code>Format GobEncode GobDecode MarshalJSON MarshalXML
Peek ReadByte ReadFrom ReadRune Scan Seek
UnmarshalJSON UnreadByte UnreadRune WriteByte
WriteTo
</code>

По умолчанию: включено.

Документация пакета: stdmethods

stdversion: сообщение об использовании символов из слишком новых версий стандартной библиотеки

Анализатор stdversion сообщает о ссылках на символы в стандартной библиотеке, которые были представлены в релизе Go, более новом, чем версия, указанная в файле. (Напоминаем, что версия Go файла определяется директивой 'go' в файле go.mod модуля или тегом сборки “//go:build go1.X” в начале файла.)

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

По умолчанию: включено.

Документация пакета: stdversion

stringintconv: проверка преобразований string(int)

Этот анализатор выявляет преобразования вида string(x), где x — целочисленный тип (но не byte или rune). Такие преобразования не рекомендуются, поскольку они возвращают UTF-8 представление кодовой точки Unicode x, а не десятичное строковое представление x, как можно было бы ожидать. Более того, если x обозначает недопустимую кодовую точку, такое преобразование не может быть статически отклонено.

Для преобразований, предназначенные для использования кодовой точки, рассмотрите возможность замены их на string(rune(x)). В противном случае, strconv.Itoa и его аналоги возвращают строковое представление значения в нужной системе счисления.

По умолчанию: включено.

Документация пакета: stringintconv

structtag: проверка соответствия тегов полей структур функции reflect.StructTag.Get

Также сообщать об использовании определённых тегов структур (json, xml), применяемых с неэкспортируемыми полями.

По умолчанию: включено.

Документация пакета: structtag

testinggoroutine: сообщать о вызовах (*testing.T).Fatal из горутин, запущенных тестом

Функции, которые внезапно завершают тест, такие как методы Fatal, Fatalf, FailNow и Skip{,f,Now} типа *testing.T, должны вызываться непосредственно из тестовой горутины. Этот анализатор обнаруживает вызовы этих функций внутри горутины, запущенной тестом. Например:

<code>func TestFoo(t *testing.T) {
  go func() {
    t.Fatal("oops") // ошибка: (*T).Fatal вызвана из не-тестовой горутины
  }()
}
</code>

По умолчанию: включено.

Документация пакета: testinggoroutine

tests: проверять распространённые ошибочные использования тестов и примеров

Анализатор tests просматривает функции Test, Benchmark, Fuzzing и Example, проверяя неправильно оформленные имена, неверные сигнатуры и примеры, описывающие несуществующие идентификаторы.

Пожалуйста, ознакомьтесь с документацией по пакету testing в golang.org/pkg/testing для ознакомления с соглашениями, соблюдаемыми для Tests, Benchmarks и Examples.

По умолчанию: включено.

Документация пакета: tests

timeformat: проверять вызовы (time.Time).Format или time.Parse с форматом 2006-02-01

Анализатор timeformat ищет форматы даты вида 2006-02-01 (гггг-дд-мм). Международно, формат «гггг-дд-мм» не используется в стандартных календарных форматах дат, поэтому более вероятно, что имелось в виду 2006-01-02 (гггг-мм-дд).

По умолчанию: включено.

Документация пакета: timeformat

unmarshal: сообщать о передаче неуказательных или неинтерфейсных значений в unmarshal

Анализатор unmarshal сообщает о вызовах функций, таких как json.Unmarshal, в которых аргумент не является указателем или интерфейсом.

По умолчанию: включено.

Документация пакета: unmarshal

unreachable: проверять наличие недостижимого кода

Анализатор unreachable находит инструкции, которые не могут быть достигнуты в процессе выполнения, поскольку перед ними находится инструкция return, вызов panic, бесконечный цикл или аналогичные конструкции.

По умолчанию: включено.

Документация пакета: unreachable

unsafeptr: проверять некорректные преобразования uintptr в unsafe.Pointer

Анализатор unsafeptr сообщает о потенциально некорректном использовании unsafe.Pointer для преобразования целых чисел в указатели. Преобразование из uintptr в unsafe.Pointer является некорректным, если предполагается, что слово в памяти имеет тип uintptr и содержит значение указателя, потому что такое слово будет невидимо для копирования стека и сборщика мусора.

По умолчанию: включено.

Документация пакета: unsafeptr

unusedfunc: проверка на неиспользуемые функции, методы и т.д.

Анализатор unusedfunc сообщает о функциях и методах, которые не используются вне собственного объявления.

Функция считается неиспользуемой, если она не экспортируется и не ссылается (за исключением ссылок внутри собственного объявления).

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

Инструмент может сообщать о ложноположительных результатах в некоторых ситуациях, например:

См. https://github.com/golang/go/issues/71686 для обсуждения этих ограничений.

Алгоритм unusedfunc не такой точный, как инструмент golang.org/x/tools/cmd/deadcode, но он имеет преимущество в том, что работает внутри модульной аналитической среды, позволяя получать почти мгновенную обратную связь в gopls.

Анализатор unusedfunc также сообщает о неиспользуемых типах, переменных и константах. Перечисления – константы, определённые с помощью iota – игнорируются, поскольку даже неиспользуемые значения должны оставаться, чтобы сохранить логическую последовательность.

По умолчанию: включено.

Документация пакета: unusedfunc

unusedparams: проверка на неиспользуемые параметры функций

Анализатор unusedparams проверяет функции на наличие параметров, которые не используются.

Для обеспечения корректности он игнорирует:

Анализатор предлагает исправление, заменяя имя параметра на «_», но в таких случаях можно получить более глубокое исправление, вызвав действие «Refactor: remove unused parameter» (рефакторинг: удалить неиспользуемый параметр), которое полностью удаляет параметр, а также все соответствующие аргументы в местах вызова, сохраняя при этом все побочные эффекты в выражениях аргументов; см. https://github.com/golang/tools/releases/tag/gopls%2Fv0.14.

Этот анализатор игнорирует сгенерированный код.

По умолчанию: включено.

Документация пакета: unusedparams

unusedresult: проверка на неиспользуемые результаты вызовов некоторых функций

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

Набор функций может управляться с помощью флагов.

По умолчанию: включено.

Документация пакета: unusedresult

unusedvariable: проверяет на неиспользуемые переменные и предлагает исправления

По умолчанию: включено.

Документация пакета: unusedvariable

unusedwrite: проверяет на неиспользуемые записи

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

Например:

<code>type T struct { x int }
func f(input []T) {
  for i, v := range input {  // v является копией
  v.x = i  // неиспользуемая запись в поле x
}
}
</code>

Другой пример касается неуказателя на получателя:

<code>type T struct { x int }
func (t T) f() {  // t является копией
t.x = i  // неиспользуемая запись в поле x
}
</code>

По умолчанию: включено.

Документация пакета: unusedwrite

waitgroup: проверяет на неправильное использование sync.WaitGroup

Этот анализатор обнаруживает ошибочные вызовы метода (*sync.WaitGroup).Add изнутри новой горутины, что приводит к гонке между Add и Wait:

<code>// НЕПРАВИЛЬНО
var wg sync.WaitGroup
go func() {
  wg.Add(1) // "WaitGroup.Add called from inside new goroutine"
  defer wg.Done()
  ...
}()
wg.Wait() // (может завершиться преждевременно до запуска новой горутины)
</code>

Правильный код вызывает Add до запуска горутины:

<code>// ПРАВИЛЬНО
var wg sync.WaitGroup
wg.Add(1)
go func() {
  defer wg.Done()
  ...
}()
wg.Wait()
</code>

По умолчанию: включено.

Документация пакета: waitgroup

yield: сообщает о вызовах yield, когда результат игнорируется

После того как функция yield возвращает false, вызывающая сторона не должна снова вызывать функцию yield; обычно итератор должен завершиться немедленно.

В этом примере не проверяется результат вызова yield, что приводит к диагностике от этого анализатора:

<code>yield(1) // yield может быть вызван снова (на строке L2) после возвращения false
yield(2)
</code>

Исправленный код выглядит следующим образом:

<code>if yield(1) { yield(2) }
</code>

или просто:

<code>_ = yield(1) && yield(2)
</code>

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

<code>yield(1) // допустимо игнорировать результат
return
</code>

Ошибка возникает только тогда, когда вызов yield, который вернул false, может быть последован другим вызовом.

По умолчанию: включено.

Документация пакета: yield


Исходные файлы этой документации можно найти ниже golang.org/x/tools/gopls/doc.

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

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