fmt.Stringer în Go

Interfața tipurilor care știu să se descrie ca text: fmt folosește metoda String() la afișare.

Sintaxă
type Stringer interface {
	String() string
}

Ce face fmt.Stringer

fmt.Stringer este o interfață cu o singură metodă: String() string. Orice tip care are această metodă o implementează automat (în Go nu scrii „implements”).

Când afișezi o valoare cu Println, Print sau cu verbele %v și %s, pachetul fmt verifică dacă valoarea este un Stringer; dacă da, afișează rezultatul lui String() în loc de formatul implicit. Așa poți afișa frumos o structură, o monedă sau o constantă dintr-o enumerare.

Atenție la receptor: dacă metoda este definită pe pointer (func (p *Produs) String()), doar *Produs are metoda, iar o valoare Produs se afișează cu formatul implicit.

Ce returnează

Metoda String() returnează textul care descrie valoarea.

Exemple

Exemplul 1: O structură care se afișează frumos

%v și %s folosesc metoda String(). Verbul %d cere un număr, deci fmt afișează câmpurile structurii ca numere, fără String().

package main

import "fmt"

type Pret struct {
	Lei, Bani int
}

func (p Pret) String() string {
	return fmt.Sprintf("%d,%02d lei", p.Lei, p.Bani)
}

func main() {
	p := Pret{12, 5}
	fmt.Println("Prețul:", p)
	fmt.Printf("%v | %s | %d\n", p, p, p)
	cos := []Pret{{3, 50}, {10, 0}}
	fmt.Println(cos)
}

Rezultat

Prețul: 12,05 lei
12,05 lei | 12,05 lei | {12 5}
[3,50 lei 10,00 lei]

Exemplul 2: Enumerare cu nume citibile

iota dă constante 0, 1, 2. Metoda String transformă numărul în numele zilei.

package main

import "fmt"

type Zi int

const (
	Luni Zi = iota
	Marti
	Miercuri
)

func (z Zi) String() string {
	switch z {
	case Luni:
		return "luni"
	case Marti:
		return "marți"
	case Miercuri:
		return "miercuri"
	}
	return fmt.Sprintf("Zi(%d)", int(z))
}

func main() {
	fmt.Println(Luni, Marti, Miercuri, Zi(7))
	var s fmt.Stringer = Marti
	fmt.Println("prin interfață:", s.String())
}

Rezultat

luni marți miercuri Zi(7)
prin interfață: marți

Exemplul 3: Receptor pointer: când String() nu este folosit

package main

import "fmt"

type Elev struct{ Nume string }

func (e *Elev) String() string { return "elevul " + e.Nume }

func main() {
	e := Elev{"Ana"}
	fmt.Println(e)  // valoare: formatul implicit
	fmt.Println(&e) // pointer: se folosește String()
}

Rezultat

{Ana}
elevul Ana

Greșeli frecvente

  • Scrii în String() fmt.Sprintf("%v", p) pe aceeași valoare. Sprintf cheamă din nou String() și programul intră în recursivitate infinită. Formatează câmpurile, nu valoarea întreagă.
  • Definești String() pe pointer și afișezi valoarea: metoda nu este folosită. Pentru tipuri mici, definește metoda pe valoare.

Comenzi înrudite

  • fmt.Println: Afișează valorile pe ecran: Println pune spații între ele și trece la rând nou, Print nu.
  • fmt.Printf: Afișează text formatat cu %d, %s, %.2f etc.; Sprintf returnează textul, Fprintf îl scrie într-un fișier sau alt Writer.
  • fmt.FormatString: Reconstruiește directiva de formatare (ex. „%8.2f”) în metoda Format a unui tip care implementează fmt.Formatter.