Skip to content

Türler

Önceki veri türleri bölümünde Go'daki tüm yerleşik veri türleri kısaca tanıtılmıştı. Bu yerleşik temel türler, sonraki özel türlerin temelini oluşturur. Go tipik bir statik tür dilidir. Tüm değişkenlerin türleri derleme zamanında belirlenir ve programın yaşam döngüsü boyunca değişmez. Bu bölümde Go'nun tür sistemi ve temel kullanımı kısaca tanıtılacaktır.

Statik Güçlü Tip

Go statik güçlü tip bir dildir. Statik, Go'nun tüm değişken türlerinin derleme sırasında zaten belirlendiği ve programın yaşam döngüsü boyunca bir daha değişmeyeceği anlamına gelir. Go'daki kısa değişken bildirimi dinamik dillerin yazımına benzese de, değişken türü derleyici tarafından otomatik olarak çıkarılır. En temel fark, türü bir kez çıkarıldıktan sonra bir daha değişmemesidir. Dinamik diller ise tam tersidir. Bu nedenle aşağıdaki kod derlenemez. Çünkü a int türünde bir değişkendir, string atanamaz.

go
func main() {
  var a int = 64
  a = "64"
  fmt.Println(a) // cannot use "64" (untyped string constant) as int value in assignment
}

Güçlü tip, programda sıkı tür denetimi yapıldığı anlamına gelir. Tür eşleşmezse, programcıya bunu yapmaması gerektiği hemen söylenir. Dinamik diller gibi olası sonuçları çıkarmaya çalışmaz. Bu nedenle aşağıdaki kod derlenemez. Çünkü her iki tür farklıdır, işlem yapılamaz.

go
func main() {
  fmt.Println(1 + "1") // invalid operation: 1 + "1" (mismatched types untyped int and untyped string)
}

Tür Son Ekleme

Go neden tür bildirimini öne değil de sona koyar? Büyük ölçüde C dilinden ders aldığı içindir. Resmi bir örnekle etkiyi gösterelim. Bu bir fonksiyon işaretçisidir

c
int (*(*fp)(int (*)(int, int), int))(int, int)

Dürüst olmak gerekirse, dikkatli bakmazsanız bunun ne tür olduğunu anlamak zordur. Go'da benzer yazım şu şekildedir

go
f func(func(int,int) int, int) func(int, int) int

Go'nun bildirim yöntemi her zaman isim önde, tür sonda ilkesini izler. Soldan sağa okuyarak, ilk bakışta bunun bir fonksiyon olduğunu ve dönüş değerinin func(int,int) int olduğunu anlayabilirsiniz. Tür daha karmaşıklaştığında, tür son ekleme okunabilirlik açısından çok daha iyidir. Go birçok düzeyde tasarımı okunabilirlik için hizmet eder.

Tür Bildirimi

Go'da tür bildirimi kullanarak özel adlı yeni bir tür bildirebilirsiniz. Yeni bir tür bildirmek genellikle bir tür adı ve bir temel tür gerektirir. Basit örnek aşağıdaki gibidir:

go
type MyInt int64

Yukarıdaki tür bildiriminde, type anahtar kelimesi ile temel türü int64 olan MyInt adında bir tür bildirilmiştir. Go'da, her yeni bildirilen türün bir temel türe sahip olması gerekir. Ve tür adının mevcut yerleşik tanımlayıcılarla tekrarlanması önerilmez.

go
type MyInt int64

type MyFloat64 float64

type MyMap map[string]int

// Derlenebilir, ancak kullanılması önerilmez, bu mevcut türü geçersiz kılar
type int int64

Tür bildirimi ile bildirilen türler yeni türlerdir. Farklı türler işlem yapamaz. Temel tür aynı olsa bile.

go
type MyFloat64 float64

var f1 MyFloat64
var f float64
f1 = 0.2
f = 0.1
fmt.Println(f1 + f)
go
invalid operation: f1 + f (mismatched types MyFloat64 and float64)

Tür Takma Adı

Tür takma adı tür bildiriminden farklıdır. Tür takma adı sadece bir takma addır, yeni bir tür oluşturmaz. Basit örnek aşağıdaki gibidir:

go
type Int = int

Her ikisi de aynı türdür, sadece adları farklıdır. Bu nedenle işlem yapabilirler. Aşağıdaki örnek doğal olarak derlenebilir.

go
type Int = int
var a Int = 1
var b int = 2
fmt.Println(a + b)
3

Tür takma adı özellikle karmaşık türler için çok kullanışlıdır. Örneğin şimdi bir tür map[string]map[string]int var. Bu iki boyutlu bir map'tir. Şimdi bir fonksiyon parametresi map[string]map[string]int türündedir. Aşağıdaki gibi

go
func PrintMyMap(mymap map[string]map[string]int) {
   fmt.Println(mymap)
}

Bu durumda, tür bildirimi kullanmaya gerek yoktur. Çünkü ilki yeni bir tür bildirir, bu fonksiyonun parametresi olarak kullanılamaz. Tür takma adı kullanıldıktan sonra örnek şu şekildedir

go
type TwoDMap = map[string]map[string]int

func PrintMyMap(mymap TwoDMap) {
   fmt.Println(mymap)
}

Tür takma adı kullandıktan sonra daha basit görünür.

::: ipucu

Yerleşik tür any, interface{}'nin tür takma adıdır. Her ikisi tamamen eşdeğerdir, sadece adları farklıdır.

:::

Tür Dönüşümü

Go'da sadece açık tür dönüşümü vardır, örtük tür dönüşümü yoktur. Bu nedenle farklı türdeki değişkenler işlem yapamaz, parametre olarak aktarılamaz. Tür dönüşümü için ön koşul, dönüştürülen değişkenin türünün ve dönüştürülecek hedef türün bilinmesidir. Örnek aşağıdaki gibidir:

go
type MyFloat64 float64

var f1 MyFloat64
var f float64
f1 = 0.2
f = 0.1
fmt.Println(float64(f1) + f)
0.30000000000000004

MyFloat64'ı açıkça float64 türüne dönüştürerek toplama işlemi yapılabilir. Tür dönüşümünün bir diğer ön koşulu: dönüştürülen türün hedef tür tarafından temsil edilebilir (Representability) olmasıdır. Örneğin int, int64 türü tarafından temsil edilebilir, float64 türü tarafından da temsil edilebilir. Bu nedenle açık tür dönüşümü yapabilirler. Ancak int türü string ve bool türleri tarafından temsil edilemez. Bu nedenle tür dönüşümü yapamazlar.

::: ipucu

Temsil (Representability) tanımı için Referans El Kitabı - Representability adresine giderek daha fazla detay öğrenebilirsiniz.

:::

İki tür birbirini temsil edebilse bile, tür dönüşümünün sonucu her zaman doğru değildir. Aşağıdaki örneğe bakalım:

go
var num1 int8 = 1
var num2 int32 = 512
fmt.Println(int32(num1), int8(num2))
1 0

num1 doğru şekilde int32 türüne dönüştürüldü, ancak num2 dönüştürülemedi. Bu tipik bir taşma sorunudur. int32 31 bit tamsayıyı temsil edebilir, int8 sadece 7 bit tamsayıyı temsil edebilir. Yüksek hassasiyetli tamsayı düşük hassasiyetli tamsayıya dönüştürülürken yüksek basamaklar atılır ve düşük basamaklar saklanır. Bu nedenle num1'in dönüşüm sonucu 0'dır. Sayı tür dönüşümünde, genellikle küçüğün büyüğe dönüştürülmesi önerilir, büyüğün küçüğe dönüştürülmesi önerilmez.

Tür dönüşümü kullanırken, bazı türler için belirsizlikten kaçınılmalıdır. Örnek aşağıdaki gibidir:

go
*Point(p) // *(Point(p)) ile eşdeğerdir
(*Point)(p)  // p'yi *Point türüne dönüştürür
<-chan int(c)    // <-(chan int(c)) ile eşdeğerdir
(<-chan int)(c)  // c'yi <-chan int türüne dönüştürür
(func())(x)      // x'i func() türüne dönüştürür
(func() int)(x)  // x'i func() int türüne dönüştürür

Tür İddiası

Tür iddiası genellikle bir interface türündeki değişkenin belirli bir türe ait olup olmadığını belirlemek için kullanılır. Örnek aşağıdaki gibidir

go
var b int = 1
var a interface{} = b
if intVal, ok := a.(int); ok {
   fmt.Println(intVal)
} else {
   fmt.Println("error type")
}
1

interface{} boş interface türü olduğundan, boş interface türü tüm türleri temsil edebilir. Ancak int türü interface{} türünü temsil edemez. Bu nedenle tür dönüşümü kullanılamaz. Tür iddiası alt türün istenen tür olup olmadığını belirleyebilir. Tür iddiası ifadesinin iki dönüş değeri vardır. Biri tür dönüştürülmüş değer, diğeri dönüşüm sonucunun boolean değeridir.

Tür Yargısı

Go'da, switch ifadesi özel bir yazımı da destekler. Bu yazım ile farklı case'lere göre farklı mantık işleme yapılabilir. Kullanım ön koşulu giriş parametresinin interface türü olmasıdır. Örnek aşağıdaki gibidir:

go
var a interface{} = 2
switch a.(type) {
    case int: fmt.Println("int")
    case float64: fmt.Println("float")
    case string: fmt.Println("string")
}
int

::: ipucu

unsafe paketi tarafından sağlanan işlemlerle, Go'nun tür sistemini atlayabilirsiniz. Orijinal olarak derlenemeyen tür dönüşümü işlemlerini yapabilirsiniz.

:::

Golang by www.golangdev.cn edit