Menu
Coddy logo textTech

Değer ile Geçme ve Referans ile Geçme

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 21 / 107.

Go, değer ile aktarılan (pass-by-value) bir dildir. Bir değişkeni bir fonksiyona aktardığınızda, Go bu değerin bir kopyasını oluşturur. Bu, fonksiyon içindeki değişikliklerin orijinal değişkeni etkilemeyeceği anlamına gelir.

func double(n int) {
    n = n * 2
}

func main() {
    x := 10
    double(x)
    fmt.Println(x)  // 10 (değişmedi)
}

Aynısı struct'lar için de geçerlidir. Bir struct'ı bir fonksiyona geçirmek tüm alanlarını kopyalar, bu nedenle fonksiyon içindeki değişiklikler kaybolur.

type Person struct {
    Name string
    Age  int
}

func birthday(p Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(alice)
    fmt.Println(alice.Age)  // 30 (değişmedi)
}

Orijinal değeri değiştirmek için bunun yerine bir işaretçi (pointer) geçirin. İşaretçinin kendisi kopyalanır, ancak hala aynı bellek adresini gösterir; bu da orijinal veriyi değiştirmenize olanak tanır.

func birthday(p *Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(&alice)
    fmt.Println(alice.Age)  // 31 (değiştirildi!)
}

Orijinal değeri değiştirmeniz gerektiğinde veya maliyetli kopyalamadan kaçınmak için büyük struct'ları geçirirken işaretçileri kullanın. Orijinal veriyi istenmeyen değişikliklerden korumak istediğinizde ise değerleri kullanın.

challenge icon

Görev

Kolay

Struct'ları değer (value) ile geçirmek ile işaretçi (pointer) ile geçirmek arasındaki farkı gösteren bir alışveriş sepeti sistemi kuralım. Yalnızca işaretçi parametrelerinin orijinal veriyi nasıl değiştirebildiğini ilk elden göreceksiniz.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • cart.go: Name (string), Price (float64) ve Quantity (int) alanlarına sahip bir CartItem struct'ı tanımlayın. Miktarı güncellenmeye çalışan iki fonksiyon oluşturun:
    • UpdateQuantityByValue bir CartItem (değer ile) ve yeni bir miktar alır, ardından öğenin miktarını yeni değere ayarlar.
    • UpdateQuantityByPointer bir *CartItem (işaretçi) ve yeni bir miktar alır, ardından öğenin miktarını yeni değere ayarlar.
    Ayrıca CartItem üzerinde, fiyat ile miktarın çarpımını döndüren bir Total metodu oluşturun.
  • main.go: Girdiden öğe detaylarını okuyun, bir CartItem oluşturun, ardından her iki güncelleme yaklaşımını da gösterin. Önce değer fonksiyonu ile güncellemeyi deneyin ve sonucu gösterin, ardından işaretçi fonksiyonu ile güncelleyin ve sonucu tekrar gösterin.

Aşağıdaki girdiler sağlanacaktır:

  • Satır 1: Öğe adı
  • Satır 2: Fiyat (float)
  • Satır 3: Başlangıç miktarı (tam sayı)
  • Satır 4: Ayarlanacak yeni miktar (tam sayı)

Çıktı formatı:

Initial: [Name] x[Quantity] = $[Total]
After value update: [Name] x[Quantity] = $[Total]
After pointer update: [Name] x[Quantity] = $[Total]

Örneğin, Laptop, 999.99, 1 ve 3 verildiğinde çıktınız şöyle olmalıdır:

Initial: Laptop x1 = $999.99
After value update: Laptop x1 = $999.99
After pointer update: Laptop x3 = $2999.97

Değer güncellemesinden sonra miktarın nasıl 1'de kaldığına (fonksiyon bir kopyayı değiştirdi), ancak işaretçi güncellemesinden sonra nasıl 3'e değiştiğine (fonksiyon orijinali değiştirdi) dikkat edin. Toplamları iki ondalık basamakla formatlayın.

Kopya kağıdı

Go, değer ile geçilen (pass-by-value) bir dildir. Bir değişkeni bir fonksiyona geçirdiğinizde, Go o değerin bir kopyasını oluşturur, bu nedenle fonksiyon içindeki değişiklikler orijinal değişkeni etkilemez.

func double(n int) {
    n = n * 2
}

func main() {
    x := 10
    double(x)
    fmt.Println(x)  // 10 (değişmedi)
}

Aynısı struct'lar için de geçerlidir. Bir struct'ı bir fonksiyona geçirmek, tüm alanlarını kopyalar:

type Person struct {
    Name string
    Age  int
}

func birthday(p Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(alice)
    fmt.Println(alice.Age)  // 30 (değişmedi)
}

Orijinal değeri değiştirmek için bir pointer (işaretçi) geçirin. Pointer'ın kendisi kopyalanır, ancak hala aynı bellek adresini işaret eder:

func birthday(p *Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(&alice)
    fmt.Println(alice.Age)  // 31 (değiştirildi!)
}

Orijinal değeri değiştirmeniz gerektiğinde veya maliyetli kopyalamadan kaçınmak için büyük struct'lar geçirirken pointer'ları kullanın. Orijinal veriyi istenmeyen değişikliklerden korumak istediğinizde ise değerleri kullanın.

Kendin dene

package main

import (
	"fmt"
)

func main() {
	// Girdiyi oku
	var name string
	var price float64
	var initialQty, newQty int

	fmt.Scanln(&name)
	fmt.Scanln(&price)
	fmt.Scanln(&initialQty)
	fmt.Scanln(&newQty)

	// TODO: Giriş değerleriyle bir CartItem oluşturun

	// TODO: Şu formatı kullanarak başlangıç durumunu yazdırın:
	// fmt.Printf("Initial: %s x%d = $%.2f\n", ...)

	// TODO: UpdateQuantityByValue kullanarak miktarı güncellemeyi deneyin
	// Ardından sonucu yazdırın (miktarın değişmediğine dikkat edin)

	// TODO: UpdateQuantityByPointer kullanarak miktarı güncelleyin
	// Ardından sonucu yazdırın (miktarın değişeceğine dikkat edin)
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler