Рассмотрим следующий пример, иллюстрирующий вопрос (он был создан только для того, чтобы пояснить вопрос, но я видел похожий код и в книгах, и в реальных проектах):
package main
import (
"strconv"
"fmt"
"log"
)
func main() {
n1, err := strconv.Atoi("1")
if err != nil {
log.Panicf("%v", err)
}
n2, err := strconv.Atoi("2")
if err != nil {
log.Panicf("%v", err)
}
// err := fmt.Errorf("new error") <- line 1
// n1, err := strconv.Atoi("3") <- line 2
fmt.Printf("n1 = %d, n2 = %d\n", n1, n2)
}
Компилятор не жалуется на переопределение err, но если я раскомментирую <- line 1 или <- line 2, он будет жаловаться no new variable on left side of :=.
Итак, как это работает? Почему компилятор с радостью позволяет переопределить err в операторе множественного возврата, используя :=, но не n1 в примере <- line 2?
Лучше, если вы можете указать на официальную ссылку, объясняющую это поведение.
Ответ 1 · рейтинг 21 · icza
Это потому, что вы использовали краткое объявление переменной :=. Цитата из спецификации:
В отличие от обычных объявлений переменных, короткое объявление переменной может повторно объявлять переменные при условии, что они были первоначально объявлены ранее в том же блоке (или в списках параметров, если блок является телом функции) с тем же типом и, по крайней мере, одна из не-пустых переменных является новой. Как следствие, повторное объявление может появиться только в коротком объявлении с несколькими переменными. Повторное объявление не вводит новую переменную; он просто присваивает новое значение оригиналу.
Эта строка:
n1, err := strconv.Atoi("1")
Является кратким объявлением с несколькими переменными, и все переменные в левой части являются новыми, поэтому все они будут объявлены (и назначены возвращаемые значения strconv.Atoi()).
Эта строка:
n2, err := strconv.Atoi("2")
Это короткое объявление с несколькими переменными, и n2 является новым. Таким образом, он объявляет n2 и присваивает новое значение только err, потому что err уже объявлено в том же блоке.
Эта строка:
err := fmt.Errorf("new error") <- line 1
Это не короткое объявление с несколькими переменными. Он попытается объявить err, но он уже объявлен в том же блоке, поэтому это ошибка времени компиляции.
И эта строка:
n1, err := strconv.Atoi("3") <- line 2
Это короткое объявление с несколькими переменными, но все переменные в левой части были ранее объявлены в том же блоке, поэтому это также ошибка времени компиляции ( он не вводит никаких новых переменных в левой части).
Обратите внимание, что если все переменные в левой части были ранее объявлены, просто измените объявление короткой переменной := на Assignment = заставит его работать (предполагаемые значения справа назначаются переменным на левая сторона).