vizibilitate (exportat/neexportat) în Go

Numele care încep cu literă mare sunt vizibile din alte pachete; cele cu literă mică rămân private pachetului.

Sintaxă
func Calculeaza() {}   // exportat: începe cu majusculă
func calculeaza() {}   // neexportat: doar în pachet
type Cont struct {
    Titular string     // câmp exportat
    sold    float64    // câmp neexportat
}

Ce face vizibilitate (exportat/neexportat)

Go nu are cuvinte precum public sau private. Vizibilitatea depinde doar de prima literă a numelui: majusculă = exportat (se vede din alte pachete, ca fmt.Println), literă mică = neexportat (se vede doar în pachetul în care este declarat). Regula se aplică funcțiilor, tipurilor, variabilelor, constantelor, metodelor și câmpurilor din struct-uri.

Unitatea de încapsulare este pachetul, nu tipul: orice cod din același pachet vede și numele cu literă mică. Câmpurile neexportate sunt ignorate și de encoding/json, care poate citi și scrie doar câmpurile exportate.

Un director numit internal adaugă un nivel în plus: pachetele de sub el pot fi importate doar de codul din directorul părinte al lui internal.

Exemple

Exemplul 1: Câmpuri exportate și encoding/json

parola începe cu literă mică, deci json.Marshal nu o vede.

package main

import (
    "encoding/json"
    "fmt"
)

type Utilizator struct {
    Nume   string
    Oras   string
    parola string
}

func main() {
    u := Utilizator{Nume: "Ana", Oras: "Iași", parola: "secret"}
    date, _ := json.Marshal(u)
    fmt.Println(string(date))
    fmt.Println("în același pachet văd parola:", u.parola)
}

Rezultat

{"Nume":"Ana","Oras":"Iași"}
în același pachet văd parola: secret

Exemplul 2: Un pachet cu API exportat (proiect pe mai multe fișiere)

Din main se pot folosi doar banca.Cont, banca.ContNou și metodele cu majusculă.

// banca/cont.go
package banca

import "errors"

type Cont struct {
    Titular string
    sold    float64 // nu se poate modifica direct din alt pachet
}

func ContNou(titular string) *Cont { return &Cont{Titular: titular} }

func (c *Cont) Depune(suma float64) { c.sold += suma }

func (c *Cont) Retrage(suma float64) error {
    if suma > c.sold {
        return errors.New("fonduri insuficiente")
    }
    c.sold -= suma
    return nil
}

func (c *Cont) Sold() float64 { return c.sold }

// main.go
package main

import (
    "fmt"

    "exemplu.ro/magazin/banca"
)

func main() {
    c := banca.ContNou("Ana")
    c.Depune(500)
    fmt.Println(c.Retrage(800))
    fmt.Println(c.Titular, c.Sold())
    // c.sold = 1000000 // eroare: c.sold undefined (cannot refer to unexported field sold)
}

Rezultat

fonduri insuficiente
Ana 500

Greșeli frecvente

  • Câmpuri cu literă mică într-un struct trimis la json.Marshal: ies goale ({}) fără nicio eroare.
  • Accesarea unui nume neexportat din alt pachet: cannot refer to unexported name banca.sold sau undefined.
  • Exportarea tuturor numelor „ca să meargă”: exportă doar ce trebuie să folosească alte pachete.

Comenzi înrudite

  • package și pachetul main: Fiecare fișier Go începe cu package; pachetul main cu funcția main() devine un program executabil.
  • module și pachete: Un pachet este un director cu fișiere .go; un modul (go.mod) este un proiect cu mai multe pachete și dependențele lor.
  • struct și struct-uri: Grupează mai multe câmpuri cu nume și tipuri diferite într-un singur tip; baza pentru modelarea datelor în Go.
  • metode: Funcții legate de un tip prin receptor; cu receptor pointer pot modifica valoarea pe care sunt apelate.