Puntatori a struct
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 20 di 107.
Quando lavori con le struct, userai spesso i puntatori per evitare di copiare grandi strutture dati e per modificare la struct originale. Un puntatore a una struct contiene l’indirizzo di memoria di quell’istanza di struct.
Puoi creare un puntatore a struct usando l'operatore & su una struct esistente, oppure usando direttamente l'operatore di indirizzo con un literal di struct.
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 30}
ptr := &p // puntatore a una struct esistente
// Oppure crea direttamente
ptr2 := &Person{Name: "Bob", Age: 25}Go offre una comoda scorciatoia per accedere ai campi di una struct tramite un puntatore. Invece di scrivere (*ptr).Name, puoi semplicemente scrivere ptr.Name. Go dereferenzia automaticamente il puntatore per te.
ptr := &Person{Name: "Alice", Age: 30}
// Both work identically
fmt.Println((*ptr).Name) // explicit dereference
fmt.Println(ptr.Name) // automatic dereferenceQuesta dereferenziazione automatica si applica anche quando si modificano i campi. Le modifiche apportate tramite il puntatore influiscono sulla struct originale.
p := Person{Name: "Alice", Age: 30}
ptr := &p
ptr.Age = 31 // modifica l'originale
fmt.Println(p.Age) // 31I puntatori a struct sono essenziali nei modelli OOP di Go. Consentono ai metodi di modificare lo stato del ricevitore, permettono di passare in modo efficiente struct di grandi dimensioni alle funzioni e costituiscono la base per creare strutture dati collegate come alberi e liste.
Sfida
FacileCreiamo un sistema di conti bancari che mostri come i puntatori a struct consentano di modificare in modo efficiente i dati originali. Creerai un conto che può essere aggiornato tramite operazioni con i puntatori.
Organizzerai il codice in due file:
account.go: Definisci una structBankAccountcon i campiOwner(string),Balance(float64) eAccountNumber(string). Crea una funzione chiamataNewAccountche accetti come parametri il nome del titolare e il numero di conto e restituisca un puntatore a una nuovaBankAccountcon saldo iniziale pari a 0. Crea anche una funzioneDepositche accetti un puntatore*BankAccounte un importo, quindi aggiunga quell'importo al saldo del conto tramite il puntatore.main.go: Leggi le informazioni del conto dall'input, crea un conto usando la tua funzione costruttore (che restituisce un puntatore), effettua un deposito usando il puntatore e visualizza i dettagli del conto per confermare che il saldo è stato modificato.
Verranno forniti i seguenti input:
- Riga 1: Nome del titolare
- Riga 2: Numero di conto
- Riga 3: Importo del deposito (float)
Formato dell'output:
Account: [AccountNumber]
Owner: [Owner]
Balance: [Balance]Ad esempio, dati John Smith, ACC-12345 e 500.50, l'output dovrebbe essere:
Account: ACC-12345
Owner: John Smith
Balance: 500.50Ricorda che la tua funzione NewAccount dovrebbe restituire *BankAccount usando l'operatore &, e che la tua funzione Deposit può modificare direttamente il saldo tramite il puntatore usando il dereferenziamento automatico di Go (ad esempio, account.Balance invece di (*account).Balance).
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Leggi il nome del titolare
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// Leggi il numero di conto
accountNumber, _ := reader.ReadString('\n')
accountNumber = strings.TrimSpace(accountNumber)
// Leggi l'importo del deposito
amountStr, _ := reader.ReadString('\n')
amountStr = strings.TrimSpace(amountStr)
amount, _ := strconv.ParseFloat(amountStr, 64)
// TODO: Crea un nuovo conto usando la funzione NewAccount (restituisce un puntatore)
// TODO: Effettua un deposito usando la funzione Deposit con il puntatore al conto
// TODO: Stampa i dettagli del conto nel formato richiesto:
// Conto: [AccountNumber]
// Titolare: [Owner]
// Saldo: [Balance]
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online