import nyilatkozatok a Go-ban

div >

Jan 15, 2018 · 6 min olvasni

programok go alkotják csomagok. Általában a csomag más csomagoktól függ, akár a szokásos könyvtárba beépített csomagoktól, akár a 3.partiktól. A csomagot először importálni kell az exportált azonosítók használatához. Ez történik construct nevű import nyilatkozat:

package mainimport (
"fmt"
"math"
)func main() {
fmt.Println(math.Exp2(10)) // 1024
}

fent már egy import nyilatkozat két ImportSpecs. Minden ImportSpec meghatározza az egyetlen csomag importálását.

A main nevű csomagot futtatható bináris fájlok létrehozására használják. A program végrehajtása a package main-ban kezdődik, hívva annak funkcióját, amelyet main-nak is neveznek.

de… vannak más, kevésbé ismert lehetőségek, amelyek hasznosak a különböző forgatókönyvek:

import (
"math"
m "math"
. "math"
_ "math"
)

e négy import specifikáció mindegyike másképp viselkedik, és ebben a bejegyzésben elemezzük ezeket a különbségeket.

a csomag importálása csak az importált csomagból exportált azonosítókra hivatkozhat. Az exportált azonosítók Unicode nagybetűvel kezdődnek – https://golang.org/ref/spec#Exported_identifiers.

az import deklaráció anatómiája

ImportDeclaration = "import" ImportSpec
ImportSpec = ImportPath
  • az azonosító minden olyan érvényes azonosító, amelyet a minősített azonosítókban használnak
  • az Importútvonal szó szerinti (nyers vagy értelmezett)

nézzünk néhány példát:

import . "fmt"
import _ "io"
import log "github.com/sirupsen/logrus"
import m "math"

faktorált import nyilatkozat

két vagy több csomag importálása kétféle módon írható. Vagy írhatunk több behozatali nyilatkozatot:

import "io"
import "bufio"

vagy használhatunk faktorált import deklarációt (több ImportSpec használatával egyetlen import deklaráción belül):

import (
"io"
"bufio"
)

a 2.opció különösen akkor hasznos, ha a csomag sok importot tartalmaz, majd megismétli a import kulcsszó sokszor csökkenti az olvashatóságot. Néhány billentyűleütést is elmenti, ha nem használ olyan eszközöket, mint a https://github.com/bradfitz/goimports, amelyek automatikusan rögzítik az importot.

(rövid) import útvonal

String literal használt import specifikáció (minden import nyilatkozat tartalmaz egy vagy több import specifikáció) megmondja, hogy milyen csomagot importálni. Ezt a karakterláncot import elérési útnak hívják. A nyelvi specifikáció szerint az implementációtól függ, hogy az importálási útvonal (string) hogyan értelmezhető, de a valós életben ez az elérési út relatív csomag szállítói könyvtár vagy `go env GOPATH`/src (További információ a GOPATH-ról).

A beépített csomagokat rövid importálási útvonalakkal importálják, mint például"math" vagy"fmt".

anatómiája .go fájl

szerkezete minden .a go fájl ugyanaz. Az első a csomag záradék opcionálisan előzi meg a megjegyzéseket, amelyek általában leírják a csomag célját. Ezután nulla vagy több behozatali nyilatkozat. A 3. szakasz nulla vagy több legfelső szintű deklarációt tartalmaz (forráskód):

// description...
package main // package clause// zero or more import declarations
import (
"fmt"
"strings"
)import "strconv"// top-level declarationsfunc main() {
fmt.Println(strings.Repeat(strconv.FormatInt(15, 16), 5))
}

a kényszerített szervezet nem teszi lehetővé a felesleges rendetlenség bevezetését, amely egyszerűsíti az elemzést és alapvetően a kódbázison keresztüli navigációt (az import deklarációkat nem lehet a csomag záradék elé helyezni, és nem lehet átfedni a felső szintű deklarációkkal, így mindig könnyű megtalálni).

az Importálás hatóköre

az Importálás hatóköre a fájlblokk. Ez azt jelenti, hogy az egész fájlból elérhető, de nem a teljes csomagon belül:

// github.com/mlowicki/a/main.go
package mainimport "fmt"func main() {
fmt.Println(a)
}// github.com/mlowicki/a/foo.go
package mainvar a int = 1func hi() {
fmt.Println("Hi!")
}

Az ilyen program nem fordítható le:

> go build
# github.com/mlowicki/a
./foo.go:6:2: undefined: fmt

További információ a hatókörökről az előző bejegyzések egyikében:

egyéni Csomagnév

egyezmény szerint az importálási útvonal utolsó összetevője az importált Csomag neve is. Természetesen semmi sem akadályoz meg minket abban, hogy ne kövessük ezt a konvenciót:

# github.com/mlowicki/main.go
package mainimport (
"fmt"
"github.com/mlowicki/b"
)func main() {
fmt.Println(c.B)
}# github.com/mlowicki/b/b.go
package cvar B = "b"

A kimenet egyszerűen b. Bár lehetséges, az egyezmény betartása általában jobb — különféle eszközök függenek tőle.

Ha az egyéni Csomagnév nincs megadva az import specifikációban, akkor a name from package záradék az importált csomag exportált azonosítóinak hivatkozására szolgál:

package mainimport "fmt"func main() {
fmt.Println("Hi!")
}

lehetőség van egyedi Csomagnév átadására az importáláshoz:

# github.com/mlowicki/b/b.go
package bvar B = "b"package mainimport (
"fmt"
c "github.com/mlowicki/b"
)func main() {
fmt.Println(c.B)
}

és az eredmény ugyanaz, mint korábban. Ez a forma az import hasznos lehet, ha már csomag, amely ugyanazt a felületet (exportált azonosítók), mint a többi csomag. Az egyik ilyen példa a https://github.com/sirupsen/logrus, amelynek API-ja kompatibilis a naplóval:

import log "github.com/sirupsen/logrus"

Ha csak a beépített naplócsomagban található API-t használjuk, akkor az ilyen Importálás cseréje import "log" nem igényel semmilyen változtatást a forráskódban. Ez egy kicsit rövidebb (de még mindig értelmes), így megmenthet néhány billentyűleütést.

minden exportált azonosító az importáló blokkba

importálási mintával:

import m "math"
import "fmt"

lehet hivatkozni az exportált azonosítóra az import specifikációban átadott csomagnévvel (m.Exp) vagy az importált csomag csomagzáradékából származó névvel (fmt.Println). Van egy másik lehetőség, amely lehetővé teszi az exportált azonosító elérését minősített azonosító nélkül:

package mainimport (
"fmt"
. "math"
)func main() {
fmt.Println(Exp2(6)) // 64
}

mikor lehet hasznos? A teszteken. Tegyük fel, hogy az a csomagot a B csomag importálja. most teszteket akarunk hozzáadni az a csomaghoz. Ha a tesztek szintén az a csomagban lesznek, és a tesztek a b csomagot is importálják (mert akkor valamit ott kell végrehajtani), akkor a körkörös függőséghez jutunk, ami tilos. Az egyik módja annak, hogy megkerülje, hogy a teszteket külön csomagba tegye, mint például az a_tests. Ezután importálnunk kell az a csomagot, és hivatkoznunk kell minden exportált azonosítóra minősített azonosítóval. Ahhoz, hogy az életünk könnyebb tudjuk importálni csomag a dot :

import . "a"

majd hivatkozzon az a csomag exportált azonosítóira Csomagnév nélkül (csakúgy, mint amikor a tesztek ugyanabban a csomagban voltak, de a nem exportált azonosítók nem érhetők el).

lehetetlen két csomagot importálni a dot használatával csomagnévként, ha legalább egy közös exportált azonosítóval rendelkeznek:

# github.com/mlowicki/c
package cvar V = "c"# github.com/mlowkci/b
package bvar V = "b"# github.com/mlowicki/a
package mainimport (
"fmt"
. "github.com/mlowicki/b"
. "github.com/mlowicki/c"
)func main() {
fmt.Println(V)
}> go run main.go
# command-line-arguments
./main.go:6:2: V redeclared during import "github.com/mlowicki/c"
previous declaration during import "github.com/mlowicki/b"
./main.go:6:2: imported and not used: "github.com/mlowicki/c"

Importálás üres azonosítóval

a Golang fordítója kiabálni fog, ha a csomagot importálják és nem használják (forráskód):

package mainimport "fmt"func main() {}

Importálás ponttal, ahol az összes exportált azonosító közvetlenül hozzáadódik a fájlblokk importálásához, a forráskód építése közben is sikertelen. Az egyetlen változat, amely működik az egyik üres azonosító. Meg kell tudni, hogy mi init funkciók annak érdekében, hogy megértsük, miért van szükség, hogy import üres azonosítóval. Az init funkciók bevezetése során az egyik korábbi történet foglalkozik:

azt javasoljuk, hogy olvassa el fentről lefelé, de lényegében importálja, mint:

import _ "math"

nem kell használni csomag math importáló fájlt, de init függvény(ek) származó importált csomag kerül végrehajtásra egyébként (csomag és IT függőségek inicializálásra kerül). Hasznos, ha csak az importált csomag által végzett bootstrapping munka érdekli, de nem hivatkozunk belőle exportált azonosítókra.

A fordítás sikertelen lesz, ha a csomagot üres azonosító nélkül importálják, és egyáltalán nem használják.

körkörös import

A Go specifikáció kifejezetten tiltja a körkörös importot — amikor a csomag indirekt módon importálja magát. A legkézenfekvőbb eset az, amikor az a csomag B csomagot importál, a B csomag pedig a csomagot importál:

# github.com/mlowicki/a/main.go
package aimport "github.com/mlowicki/b"var A = b.B# github.com/mlowicki/b/main.go
package bimport "github.com/mlowicki/a"var B = a.A

a két csomag bármelyikének felépítésére tett kísérlet hibát eredményez:

> go build
can't load package: import cycle not allowed
package github.com/mlowicki/a
imports github.com/mlowicki/b
imports github.com/mlowicki/a

természetesen bonyolultabb forgatókönyv is lehet, mint például a (z) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (a) (A) (/P>

a csomag nem tudja importálni magát:

package mainimport (
"fmt"
"github.com/mlowicki/a"
)var A = "a"func main() {
fmt.Println(a.A)
}

Compiling such package also gives an error: can’t load package: import cycle not allowed.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.