Go программы создаются путем объединения пакетов. Пакет в свою очередь состоит из одного или нескольких исходных файлов, которые вместе объявляют константы, типы, переменные и функции, принадлежащие пакету, и которые доступны во всех файлах одного и того же пакета. Эти элементы могут быть экспортированы и использованы в другом пакете.
Организация исходного файла
Каждый исходный файл состоит из пункта package, определяющего пакет, к которому он принадлежит, за которым следует возможно пустой набор объявлений импорта, которые объявляют пакеты, содержимое которых он хочет использовать, за которыми следует возможно пустой набор объявлений функций, типов, переменных, и константы.
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
Пункт package
Пункт package начинает каждый исходный файл и определяет пакет, к которому принадлежит файл.
PackageClause = "package" PackageName .
PackageName = identifier .
PackageName не должно быть пустым идентификатором. Пример:
package math
Набор файлов с одинаковым PackageName формирует реализацию пакета. Реализация может потребовать, чтобы все исходные файлы пакета находились в одном каталоге.
Import объявления
В объявлении импорта указывается, что исходный файл, содержащий объявление, зависит от функциональности импортированного пакета (инициализация и выполнение программы) и обеспечивает доступ к экспортированным идентификаторам этого пакета. При импорте указывается идентификатор (PackageName), который будет использоваться для доступа, и ImportPath, который указывает импортируемый пакет.
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
PackageName используется в квалифицированных идентификаторах для доступа к экспортированным идентификаторам пакета в исходном импортирующем файле. Это объявлено в блоке файла. Если PackageName опущено, по умолчанию используется идентификатор, указанный в предложении пакета импортируемого пакета. Если вместо имени появляется явный период (.), все экспортированные идентификаторы пакета, объявленные в блоке пакета этого пакета, будут объявлены в блоке файла импортирующего исходного файла и должны быть доступны без квалификатора.
Интерпретация ImportPath зависит от реализации, но обычно является подстрокой полного имени файла скомпилированного пакета и может относиться к хранилищу установленных пакетов.
Ограничение реализации: компилятор может ограничивать ImportPaths непустыми строками, используя только символы, принадлежащие общим категориям Unicode L, M, N, P и S (графические символы без пробелов), а также может исключать символы !"#$%&'()*,:;<=>?[\]^`{|} и символ замены Unicode U+FFFD.
Предположим, что мы скомпилировали пакет, содержащий выражение пакета package math, которое экспортирует функцию Sin, и установили скомпилированный пакет в файл, обозначенный как «lib/math». В следующей таблице показано, как обращаться к Sin в файлах, которые импортируют пакет после различных типов объявлений импорта.
Import declaration локальное имя Sin
import "lib/math" math.Sin
import m "lib/math" m.Sin
import . "lib/math" Sin
Декларация импорта объявляет отношение зависимости между импортирующим и импортированным пакетом. Запрещается импортировать сам пакет, прямо или косвенно, или напрямую импортировать пакет без ссылки на какие-либо экспортируемые идентификаторы. Чтобы импортировать пакет исключительно для его побочных эффектов (инициализация), используйте пустой идентификатор в качестве явного имени пакета:
import _ "lib/math"
Пример пакета
Вот полный Go пакет, который реализует конкуррентный отсеиватель простых чисел.
package main
import "fmt"
// Отправляем последовательность 2, 3, 4, … в канал 'ch'.
func generate(ch chan<- int) {
for i := 2; ; i++ {
ch <- i // Отправляем 'i' в канал 'ch'.
}
}
// Копируем значения из канала 'src' в канал 'dst',
// удаляем те что делимы на 'prime'.
func filter(src <-chan int, dst chan<- int, prime int) {
for i := range src { // Проходим в цикле по значениям
// полученным из 'src'.
if i%prime != 0 {
dst <- i // Отправляем 'i' в канал 'dst'.
}
}
}
// Отсеиватель простых чисел:
// Гирляндный фильтр работает вместе.
func sieve() {
ch := make(chan int) // Создаем новый канал.
go generate(ch) // Запускаем generate()
// как подпроцесс.
for {
prime := <-ch
fmt.Print(prime, "\n")
ch1 := make(chan int)
go filter(ch, ch1, prime)
ch = ch1
}
}
func main() {
sieve()
}
Читайте также:
- Основы языка Go: пакеты
- Основы языка Go: импорты
- Эффективный Go: пустой идентификатор в импорте и переменных
Комментариев нет:
Отправить комментарий