Понимание переменной области в Go - PullRequest
0 голосов
/ 25 сентября 2018

Я прохожу спецификацию Go, чтобы выучить язык, и эти пункты взяты из спецификации в разделе " Объявления и область действия ."

Хотя я могу понять пункты 1-4, я запутался в пунктах 5 и 6:

Область видимости константы или идентификатора переменной, объявленной внутри функции, начинается в конце ConstSpec или VarSpec (ShortVarDecl для коротких объявлений переменных) и заканчивается в конце самого внутреннего содержащего блока. Область действияидентификатора типа, объявленного внутри функции, начинается с идентификатора в TypeSpec и заканчивается в конце самого внутреннего содержащего блока.

Это код, который я использовал для понимания области видимости в Go:

package main

import "fmt"

func main() {
    x := 42
    fmt.Println(x)
    {
        fmt.Println(x)
        y := "The test message"
        fmt.Println(y)
    }
    // fmt.Println(y) // outside scope of y
}

Из этого кода я понимаю, что область действия x находится внутри функции main, а область действия y находится внутри открывающих и закрывающих скобок после fmt.Println(x), иЯ не могу использовать y вне закрывающих скобок.

Если я правильно понимаю, оба пункта 4 и 5 говорят одно и то же.Итак, мои вопросы:

  1. Если они говорят одно и то же, какова важность обоих пунктов?

  2. Если они разные, пожалуйста, дайте мне знать разницу?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Помимо применения к различным вещам (правило № 5 предназначено для констант- и объявлений переменных , правило № 6 предназначено для объявлений типов ), существует такжеважное отличие в формулировке:

Область действия идентификатора константы или переменной, объявленного внутри функции , начинается в конце ConstSpec или VarSpec (ShortVarDecl для коротких объявлений переменных) и заканчивается в конце самого внутреннего содержащего блока. Область действия идентификатора типа, объявленного внутри функции , начинается с идентификатора в TypeSpec и заканчивается в конце самого внутреннего содержащего блока.

По этой причине существует два правила, а не одно.

Что это значит?Что означает это различие?

# 5 Объявления переменных и констант (внутри функции)

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

Это недопустимо:

f := func() {
    f()
}

Попытка компиляции:

prog.go:5:3: undefined: f

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

var f func()
f = func() {
    f()
}

Теперь здесь объявление f заканчивается закрывающей скобкой (типа func()), поэтому на следующей строке, когда мы назначаем ей анонимную функцию,допустимо ссылаться на f (для вызова значения функции, хранящегося в переменной f), потому что теперь оно находится в области видимости.См. Связанный вопрос: Определение рекурсивной функции внутри функции в Go

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

var m = map[int]string{
    1:  "one",
    21: "twenty-" + m[1],
}

Это дает ошибку времени компиляции ("undefined: m"), потому что m еще не находится в области видимости внутри составного литерала.

Иочевидно, этот обходной путь работает:

var m = map[int]string{
    1: "one",
}
m[21] = "twenty-" + m[1]

# 6 Объявления типов (внутри функции)

Область действия объявленного типа начинается с идентификатора в объявлении.Таким образом, в отличие от правила № 5, допустимо ссылаться на сам тип внутри его объявления.

Имеет ли он какое-либо преимущество / значение?

Да, вы можете объявлять рекурсивные типы, напримеркак это:

type Node struct {
    Left, Right *Node
}

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

Другим примером может быть тип слайса, чей тип элемента сам по себе:

type Foo []Foo

Подробнее об этом можно прочитать здесь: Как фрагмент может содержать сам себя?

Еще один действительный пример:

type M map[int]M
0 голосов
/ 25 сентября 2018

Они делают одно и то же, с одинаковыми правилами, о двух разных вещах: первое касается переменных и констант, второе касается идентификаторов типов.Таким образом, если вы объявляете тип внутри блока, применяются те же правила области видимости, которые применяются к переменной, объявленной в том же месте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...