Menu

Golang Paketler ve Import'lar: Dışa Açık Adlar, Birden Fazla Dosya

Go paketleri nasıl çalışır: package ifadesi, standart ve modül paketlerini import etmek, dışa açık ve dışa kapalı adlar, bir paketi dosyalara bölmek, internal paketler, import takma adları, boş import'lar ve go run main.go'dan gelen "undefined" hatası.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Her Go dosyası, ilk satırında bildirilen bir pakete aittir. Bir paketteki kod başka birini import ederek ve adların önüne paket adını koyarak kullanır. Paketin dışından yalnızca büyük harfle başlayan adlar kullanılabilir.

fmt, math ve strings standart kütüphane paketleridir. Go ile birlikte gelirler, bu yüzden birini "eklemek" adını import bloğuna yazmak demektir. Hiçbir şey indirilmez. fmt.Println, math.Sqrt ve strings.Repeat dışa açık oldukları için büyük harfle başlar.

package İfadesi

Her .go dosyasının yorum olmayan ilk satırı package name'dir. Bir dizindeki tüm dosyalar aynı adı kullanmalıdır ve birlikte tek bir paket oluştururlar. İki farklı paket adı olan bir dizin derlenmez:

found packages greeting (b.go) and greet (greet.go) in /home/ana/shop/greet

(Tek istisna package name_test kullanabilen test dosyalarıdır.)

package main özeldir: bir çalıştırılabilir dosya üretir ve program onun func main()'inden başlar. Diğer her paket import edilmek üzere tasarlanmış bir kütüphanedir.

Geleneğe göre paket adı dizin yolunun son elemanıyla eşleşir: shop/greet içindeki kod package greet'tir. Paket adları kısa, küçük harfli, tek kelimedir; alt çizgi ya da karışık büyük harf içermez: string_utils ya da greetHelpers değil, strconv, httptest, greet.

Paketleri Import Etmek

Bir import yolu bir string'dir. Standart kütüphane için Go'nun kaynak ağacındaki paketin yoludur; diğer her şey için bir modül yoluyla başlar:

import (
	"fmt"           // standard library
	"net/http"      // standard library, nested path
	"math/rand/v2"  // standard library, version 2 of math/rand

	"github.com/google/uuid"   // another module (needs go get)
	"example.com/shop/greet"   // a package in your own module
)

Yol paketin nerede yaşadığıdır; ad kodda yazdığınız şeydir. net/http için ad http, math/rand/v2 için rand'dır. http.Get yazarsınız, asla net/http.Get değil.

gofmt ve goimports bloğu sıralar ve geleneksel olarak standart kütüphane import'larını geri kalanlardan boş bir satırla ayırır.

Kullanılmayan import'lar derleme hatasıdır:

./main.go:5:2: "os" imported and not used

Go desteği olan editörler kaydederken goimports çalıştırır; bu da eksik standart import'ları ekler ve kullanılmayanları sizin yerinize kaldırır.

Dışa Açık ve Dışa Kapalı Adlar

Go'da görünürlüğe tek bir kural karar verir: bir ad büyük harfle başlıyorsa dışa açıktır. Bu, fonksiyonlar, tipler, değişkenler, sabitler, struct alanları ve metotlar için geçerlidir. public, private ya da protected anahtar kelimeleri yoktur.

AdPaketin dışından görünür mü?
func Hello()evet
func hello()hayır
type User structevet
User.Name alanıevet
User.email alanıhayır
const MaxSizeevet
var defaultTimeouthayır

Dışa kapalı bir adı başka bir paketten kullanmaya çalışmak bir undefined hatası verir:

./main.go:11:20: undefined: greet.prefix

Kural tek bir dosyanın içinde bile önemlidir, çünkü diğer paketler tiplerinizi inceler. encoding/json yalnızca dışa açık alanları görebilir:

token JSON'un dışında sessizce kalır. Alan özel veriyse bu bir özelliktir, istediğiniz bir alanı büyük harfle başlatmayı unuttuysanız bir sürprizdir.

Bir Paketi Dosyalara Bölmek

Bir paket istediğiniz kadar dosyaya yayılabilir. Dizinde aynı package satırına sahip her dosya, dışa açık olsun ya da olmasın, diğerlerinde tanımlanan her adı hiçbir şey import etmeden görür:

shop/
├── go.mod        (module example.com/shop)
├── main.go
└── math.go
// main.go
package main

import "fmt"

func main() {
	fmt.Println(total(2, 3))
}
// math.go
package main

func total(a, b int) int { return a + b }

main.go, total'ı doğrudan çağırır. Aynı paketin dosyaları arasında #include ya da import yoktur.

go run main.go'dan gelen "undefined" hatası

Bu, Go'da en çok aranan paket sorunudur ve tek bir nedeni vardır. Yalnızca main'i içeren dosyayı çalıştırmak yalnızca o dosyayı derler:

go run main.go
# command-line-arguments
./main.go:6:14: undefined: total

command-line-arguments, Go'nun bir dosya listesinden derlenen pakete verdiği addır ve math.go o listede değildir. Bunun yerine paketin tamamını çalıştırın:

go run .
5

Aynısı go build main.go için de geçerlidir. go run . ve go build (ya da go build ./cmd/app) kullanın, sorun hiç ortaya çıkmaz. go run . ile devam ederse iki dosyanın da package main dediğini ve hiçbirinin onu dışarıda bırakan bir build kısıtı (//go:build) ya da _test.go soneki olmadığını kontrol edin.

Kendi Paketleriniz

Modülünüzün bir alt dizini ayrı bir pakettir. Onu go.mod'daki modül yolu artı dizinle import edin:

shop/
├── go.mod          (module example.com/shop)
├── main.go
└── greet/
    └── greet.go
// greet/greet.go
package greet

const prefix = "Hi, "

// Hello returns a greeting for name.
func Hello(name string) string {
	return prefix + name
}
// main.go
package main

import (
	"fmt"

	"example.com/shop/greet"
)

func main() {
	fmt.Println(greet.Hello("Ana"))
}
Hi, Ana

Burada iki şey insanları zorlar. Import göreli bir yol değil, modül yolu artı dizindir: "./greet" modül modunda çalışmaz. Ve prefix küçük harfli olduğu için main'den gizli kalır; paketin API'sinin parçası yalnızca Hello'dur.

Internal Paketler

internal adlı bir dizin, içindekini kimin import edebileceğini kısıtlar. shop/internal/store içindeki kod shop/ altında kök salan her paket tarafından import edilebilir, dışındaki hiçbir şey tarafından edilemez. Deneyen başka bir modül şunu alır:

use of internal package example.com/shop/internal/store not allowed

Dünyanın geri kalanına söz vermeden kendi paketleriniz arasında paylaşmak istediğiniz kod için internal/ kullanın. Dışarıdaki hiçbir kod ona bağımlı olamayacağı için API'sini serbestçe değiştirebilirsiniz.

Import Takma Adları

Yoldan önce adı yazarak bir import'a farklı bir yerel ad verin. Olağan neden, aynı adlı iki pakettir:

İki paketin de adı rand'dır, bu yüzden en az birinin bir takma ada ihtiyacı vardır. Takma adları çakışmalar ve belirsiz adlar için kullanın; paketleri yalnızca kısaltmak için yeniden adlandırmayın, çünkü okuyanlar sizin sc'nizi değil strconv'u bilir.

Boş ve Nokta Import'ları

Boş import (_). Bir paketi yalnızca yan etkileri için import eder: paket değişkenleri ve init fonksiyonları çalışır, ama adlarından hiçbirini kullanmazsınız. Veritabanı sürücüleri ve görüntü çözücüler kendilerini böyle kaydeder:

import (
	"database/sql"

	_ "github.com/lib/pq" // registers the "postgres" driver with database/sql
)

_ olmadan import kullanılmayan import hatası olurdu.

Nokta import'u (.). Paketin dışa açık adlarını doğrudan dosyanızın kapsamına koyar, böylece fmt.Println yerine Println yazarsınız. Adların nereden geldiğini gizler ve birkaç test yardımcısı kalıbı dışında önerilmez.

Import Döngüleri

Go iki paketin birbirini doğrudan ya da bir zincir üzerinden import etmesine izin vermez:

package example.com/shop
	imports example.com/shop/greet from main.go
	imports example.com/shop/other from c.go
	imports example.com/shop/greet from o.go: import cycle not allowed

Hata zinciri listeler. İki çözüm neredeyse her durumu karşılar:

  1. İki paketin de ihtiyaç duyduğu kodu, ikisinin de import ettiği üçüncü, daha alt seviyeli bir pakete taşıyın.
  2. A paketinin yalnızca B'deki bir şeyi çağırması gerekiyorsa A'da küçük bir interface tanımlayın ve B'nin tipinin onu karşılamasına izin verin. A artık B'yi import etmez.

Bir döngü genellikle paket sınırlarının aslında birbirine ait kod katmanlarının etrafına çizildiği anlamına gelir, bu yüzden bölmeyi yeniden düşünmek için de bir işarettir.

Sık Yapılan Hatalar

  • Tek bir dosyayı çalıştırmak. Çok dosyalı bir pakette go run main.go: go run . kullanın.
  • Göreli import'lar. import "./utils" modül modunda başarısız olur. "example.com/yourmodule/utils" kullanın.
  • Dışa açmak istediğiniz küçük harfli adlar. Diğer paketlerin ihtiyaç duyduğu bir fonksiyon, alan ya da metot büyük harfle başlamalıdır.
  • Dizinle eşleşmeyen paket adı. Geçerlidir ama kafa karıştırır: import yolu utils der, kod ise helpers.X. Aynı tutun.
  • Her şeyi toplayan paket adları. util, common ve misc içerikleri hakkında hiçbir şey söylemez ve import döngüsü mıknatısına dönüşme eğilimindedir. Paketleri sağladıkları şeyle adlandırın: money, auth, slug.

Sıkça Sorulan Sorular

Go aynı paketteki bir fonksiyon için neden undefined diyor?

Muhtemelen go run main.go çalıştırdınız. Bir dosya adı vermek yalnızca o dosyayı derler, bu yüzden aynı paketin diğer dosyalarında tanımlanan fonksiyonlar eksik kalır: undefined: total. Bunun yerine dizindeki her .go dosyasını derleyen go run . çalıştırın. Ayrıca her dosyanın aynı package satırına sahip olduğunu kontrol edin.

Go'da fmt paketi nasıl eklenir?

fmt standart kütüphanenin bir parçasıdır ve Go ile birlikte gelir, bu yüzden kurulacak bir şey yoktur. package satırından sonra import "fmt" ekleyin ve fonksiyonlarını fmt. önekiyle çağırın, örneğin fmt.Println("hi"). Aynısı strings, os, time, net/http ve diğer tüm standart paketler için geçerlidir.

Go'da kendi paketimi nasıl import ederim?

Onu modül yolu artı dizinle import edin. example.com/shop adlı bir modülde greet klasöründeki bir paket import "example.com/shop/greet" olarak import edilir ve greet.Hello() olarak kullanılır. Import edene yalnızca büyük harfle başlayan adlar görünür.

Go'da exported ile unexported arasındaki fark nedir?

Büyük harfle başlayan bir ad (Hello, Total, User.Name) dışa açıktır ve diğer paketlerden kullanılabilir. Küçük harfli bir ad (hello, total, user.name) dışa kapalıdır ve yalnızca kendi paketinin içinde görünür. public ya da private anahtar kelimeleri yoktur.

Go'da "import cycle not allowed" nasıl düzeltilir?

İki paket birbirini doğrudan ya da bir zincir üzerinden import ediyor; Go bunu yasaklar. Paylaşılan kodu ikisinin de import ettiği üçüncü bir pakete taşıyın ya da davranışa ihtiyaç duyan pakette küçük bir interface tanımlayın ki artık diğerini import etmesin.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA