Menu
Coddy logo textTech

Go'da Duck Typing

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

Duck typing terimi şu deyişten gelir: "Eğer bir ördek gibi yürüyorsa ve bir ördek gibi vaklıyorsa, o zaman o bir ördektir." Go'da bu, bir türün bir arayüzü (interface) uyguladığını açıkça beyan etmesine gerek olmadığı, sadece doğru metotlara sahip olmasının yeterli olduğu anlamına gelir.

Şu arayüzü ve tamamen ilgisiz iki türü ele alalım:

type Quacker interface {
    Quack() string
}

type Duck struct{}
func (d Duck) Quack() string { return "Quack!" }

type Robot struct{}
func (r Robot) Quack() string { return "Beep-quack!" }

Ne Duck ne de Robot tanımlarının hiçbir yerinde Quacker ifadesinden bahsetmez. Yine de her ikisi de sadece doğru imzaya sahip bir Quack() metoduna sahip oldukları için arayüzü (interface) karşılarlar:

func MakeItQuack(q Quacker) {
    fmt.Println(q.Quack())
}

func main() {
    MakeItQuack(Duck{})   // Vak!
    MakeItQuack(Robot{})  // Bip-vak!
}

Bu örtük karşılama güçlüdür çünkü arayüzleri tipler zaten mevcut olduktan sonra tanımlamanıza olanak tanır. Harici paketlerdeki tiplerle eşleşen bir arayüzü, onların kaynak kodunu değiştirmeden oluşturabilirsiniz. Tiplerin sizin arayüzünüzden haberdar olması gerekmez; sadece doğru şekilde davranmaları yeterlidir.

Go'daki Duck typing, derleme zamanı tür güvenliğini korurken size dinamik dillerin esnekliğini sağlar. Derleyici, türlerin arayüz (interface) değerleri olarak kullanılmasına izin vermeden önce, bu türlerin gerekli metotlara gerçekten sahip olup olmadığını doğrular.

challenge icon

Görev

Kolay

Ördek tiplemesini (duck typing) iş başında gösteren bir mesajlaşma sistemi kuralım. Hiçbiri açıkça bir arayüzü uyguladığını (implement) belirtmeden, ortak bir arayüz üzerinden mesaj gönderebilen tamamen ilgisiz türler oluşturacaksınız.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • messengers.go: Aynı davranışı paylaşan üç ilgisiz struct oluşturun:
    • Number alanına sahip PhoneSendMessage(text string) string metodu "SMS to [Number]: [text]" değerini döndürür.
    • Email alanına sahip ComputerSendMessage(text string) string metodu "Email to [Email]: [text]" değerini döndürür.
    • Name alanına sahip PigeonSendMessage(text string) string metodu "[Name] carries: [text]" değerini döndürür.
    Bu türlerin hiçbirinin herhangi bir arayüzden bahsetmediğine dikkat edin; sadece aynı metod imzasına sahipler.
  • sender.go: SendMessage(text string) string metodunu gerektiren bir Messenger arayüzü (interface) tanımlayın. Bir Messenger dilimi (slice) ve bir mesaj dizesi alan, ardından her bir haberci üzerinde SendMessage çağrılmasının sonucunu içeren bir dize dilimi döndüren Broadcast adlı bir fonksiyon oluşturun.
  • main.go: Girdiden detayları okuyun, her haberci türünden birer tane oluşturun, bunları bir Messenger diliminde toplayın ve hepsinden bir mesaj göndermek için Broadcast fonksiyonunu kullanın. Her sonucu kendi satırında yazdırın.

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

  • Satır 1: Telefon numarası
  • Satır 2: E-posta adresi
  • Satır 3: Güvercin adı
  • Satır 4: Yayınlanacak mesaj

Örneğin, "555-1234", "alice@mail.com", "Winston" ve "Hello World" verildiğinde, çıktınız şöyle olmalıdır:

SMS to 555-1234: Hello World
Email to alice@mail.com: Hello World
Winston carries: Hello World

Buradaki temel nokta, Phone, Computer ve Pigeon türlerinin ortak hiçbir yanının olmamasıdır; bir temel türü paylaşmazlar veya Messenger arayüzünü açıkça uygulamazlar. Yine de hepsi aynı şekilde "vakvakladıkları" (eşleşen metoda sahip oldukları) için Go, hepsinin Messenger değerleri olarak kullanılmasına izin verir. İşte bu, ördek tiplemesidir (duck typing).

Kopya kağıdı

Go'da, duck typing (ördek tipleme), bir türün bir arayüzü uyguladığını açıkça belirtmesine gerek olmadığı anlamına gelir; sadece eşleşen imzalara sahip gerekli metotlara sahip olması yeterlidir.

Bir tür, arayüzün gerektirdiği tüm metotlara sahipse, o arayüzü örtük olarak karşılar:

type Quacker interface {
    Quack() string
}

type Duck struct{}
func (d Duck) Quack() string { return "Quack!" }

type Robot struct{}
func (r Robot) Quack() string { return "Beep-quack!" }

Hem Duck hem de Robot, tanımlarında belirtilmemesine rağmen Quacker arayüzünü karşılar:

func MakeItQuack(q Quacker) {
    fmt.Println(q.Quack())
}

func main() {
    MakeItQuack(Duck{})   // Quack!
    MakeItQuack(Robot{})  // Beep-quack!
}

Bu örtük karşılama, türler zaten mevcut olduktan sonra arayüzler tanımlamanıza ve hatta kaynak kodlarını değiştirmeden harici paketlerdeki türlerle eşleşen arayüzler oluşturmanıza olanak tanır. Derleyici, türlerin gerekli metotlara sahip olduğunu derleme zamanında doğrulayarak, esnekliği korurken tip güvenliği sağlar.

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Telefon numarasını oku
	scanner.Scan()
	phoneNumber := scanner.Text()
	
	// E-posta adresini oku
	scanner.Scan()
	email := scanner.Text()
	
	// Güvercin adını oku
	scanner.Scan()
	pigeonName := scanner.Text()
	
	// Yayınlanacak mesajı oku
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: Her haberci türünden (Phone, Computer, Pigeon) birer tane oluşturun
	
	// TODO: Tüm habercileri bir Messenger dilimi (slice) içinde toplayın
	
	// TODO: Mesajı tüm haberciler aracılığıyla göndermek için Broadcast kullanın
	
	// TODO: Her sonucu kendi satırına yazdırın
	
	// Değişkenleri kullanmak için yer tutucu (uygularken kaldırın)
	_ = phoneNumber
	_ = email
	_ = pigeonName
	_ = message
}
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