Section 02.6 turkish language support added.
This commit is contained in:
412
tr/02.6.md
Normal file
412
tr/02.6.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# 2.6 Interface
|
||||
|
||||
## Interface (Arabirim)
|
||||
|
||||
Go' nun göze çarpan özelliklerinden biri interfacelerdir. Türkçeye arabirim diyerek de çevrilebilir. Bu bölümü okuduktan sonra, interfacelerin kullanımı muhtemelen anlamış olacaksınız.
|
||||
|
||||
### Interface nedir?
|
||||
|
||||
Interface bir grup methodun özelliklerini, yapması gerekenleri tanımlamak için kullandığımız bir sooyutlama yöntemidir. Nesnelere uygulanacak kontrat ya da şartad olarak düşünebiliriz.
|
||||
|
||||
Önceki bölümlerdeki gibi, Ogrenci hem de Calisan `Merhaba()` yapabilir, ancak aynı şeyi yapmış olmazlar.
|
||||
|
||||
Ogrenciye `BorcPara()` , Calisana ise `MaasHarca () ` ve `SarkiSoyle ()` yöntemi ekleyeceğiz.
|
||||
|
||||
Şimdi, Ogrenci'nin `Merhaba ()`,`SarkiSoyle () `ve` BorcPara () `olarak üç methodu, Calisan'ın ise `Merhaba () `,`SarkiSoyle () `ve` MaasHarca () ` methodları vardır.
|
||||
|
||||
Bu yöntem topluluğuna interface(arairim) denir ve hem Ogrenci hem de Calisan tarafından uygulanır. Böylece, Ogrenci ve Calisan `Merhaba ()` ve `SarkiSoyle ()` interfacelerini uygulamış olur.
|
||||
Bununla birlikte, Calisan `BorcPara ()`, Ogrenci ise `MaasHarca ()` arayüzünü uygulamıyor. Bunun nedeni Calisan'ın `BorcPara ()` , Ogrenci'nin ise `MaasHarca ()` yöntemine sahip olmamasıdır.
|
||||
|
||||
### Interface Type'ları (türleri)
|
||||
|
||||
Interface'ler aslında bir dizi methodtur yani eğer type, tüm interface methodlarını uygularsa biz ona interface'i implemente ediyor(uyguluyor) deriz.
|
||||
|
||||
```Go
|
||||
type Insan struct {
|
||||
ad string
|
||||
yas int
|
||||
telefon string
|
||||
}
|
||||
|
||||
type Ogrenci struct {
|
||||
Insan
|
||||
okul string
|
||||
kredi float32
|
||||
}
|
||||
|
||||
type Calisan struct {
|
||||
Insan
|
||||
sirket string
|
||||
para float32
|
||||
}
|
||||
|
||||
// define interfaces
|
||||
type Adamlar interface {
|
||||
Merhaba()
|
||||
SarkiSoyle(sarkiSozu string)
|
||||
HunharcaYemek(beerStein string)
|
||||
}
|
||||
|
||||
type Delikanli interface {
|
||||
Merhaba()
|
||||
SarkiSoyle(song string)
|
||||
BorcPara(amount float32)
|
||||
}
|
||||
|
||||
type IhtiyarDelikanli interface {
|
||||
Merhaba()
|
||||
SarkiSoyle(song string)
|
||||
MaasHarca(amount float32)
|
||||
}
|
||||
|
||||
func (i *Insan) Merhaba() {
|
||||
fmt.Printf("Selam, Ben %s beni şöyle çağırabilirsin %s\n", h.ad, h.telefon)
|
||||
}
|
||||
|
||||
func (i *Insan) SarkiSoyle(sarkiSozu string) {
|
||||
fmt.Println("La la, la la la, la la la la la...", sarkiSozu)
|
||||
}
|
||||
|
||||
func (i *Insan) HunharcaYemek(beerStein string) {
|
||||
fmt.Println("Yumm yumm yummm hunharca tüketiyorum...", beerStein)
|
||||
}
|
||||
|
||||
// Calisan overloads Merhaba
|
||||
func (e *Calisan) Merhaba() {
|
||||
fmt.Printf("Selam, ben %s, %s 'de calısıyorum. Beni söyle cağırabilirsin %s\n", e.ad,
|
||||
e.sirket, e.telefon)
|
||||
}
|
||||
|
||||
func (s *Ogrenci) BorcPara(amount float32) {
|
||||
s.kredi += amount
|
||||
}
|
||||
|
||||
func (e *Calisan) MaasHarca(amount float32) {
|
||||
e.para -= amount
|
||||
}
|
||||
```
|
||||
Artık interface'in herhangi bir type(tür) tarafından uygulanabileceğini ve bir type'ın aynı anda birçok interface'i uygulayabileceğini biliyoruz.
|
||||
|
||||
Herhangi bir type'ın boş `interface {}` uyguladığını unutmayın, çünkü herhangi bir methodu yoktur ve tüm typeların varsayılan olarak sıfır methodu vardır.
|
||||
|
||||
### Interface degeri
|
||||
|
||||
Peki interface' e ne tür değerler koyulabilir? Bir değişkeni, type interface olarak tanımlarsak, interface'i uygulayan herhangi bir type bu değişkene atanabilir.
|
||||
|
||||
Aşağıdaki örnekte olduğu gibi, Adamlar' a interface olarak bir "m" değişkeni tanımlarsak, Ogrenci, Insan veya Calisan'dan herhangi biri "m" değişkenine atanabilir. Ve elimizde Adamlar' dan bir parça(slice) olabilir. Ve Adamlar' ı implement eden(uygulayan) herhangi bir type'dan bir parça' da bu değişkene atanabilir.
|
||||
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Insan struct {
|
||||
ad string
|
||||
yas int
|
||||
telefon string
|
||||
}
|
||||
|
||||
type Ogrenci struct {
|
||||
Insan
|
||||
okul string
|
||||
kredi float32
|
||||
}
|
||||
|
||||
type Calisan struct {
|
||||
Insan
|
||||
sirket string
|
||||
para float32
|
||||
}
|
||||
|
||||
// Interface Adamlar, Insan'dan implemente edildi.
|
||||
type Adamlar interface {
|
||||
Merhaba()
|
||||
SarkiSoyle(sarkiSozu string)
|
||||
}
|
||||
|
||||
// method
|
||||
func (h Insan) Merhaba() {
|
||||
fmt.Printf("Selam, Ben %s, Beni şu numaradan arayabilrsin: %s\n", h.ad, h.telefon)
|
||||
}
|
||||
|
||||
// method
|
||||
func (h Insan) SarkiSoyle(sarkiSozu string) {
|
||||
fmt.Println("La la la la...", sarkiSozu)
|
||||
}
|
||||
|
||||
// method
|
||||
func (e Calisan) Merhaba() {
|
||||
fmt.Printf("Selam, ben %s, %s ' da çalışıyorum. Beni şu numaradan arayabilrsin: %s\n", e.ad,
|
||||
e.sirket, e.telefon) //Evet, iki satıra ayırabiliriz.
|
||||
}
|
||||
|
||||
func main() {
|
||||
ali := Ogrenci{Insan{"Ali", 20, "222-222-XXX"}, "ODTU", 0.00}
|
||||
ahmet := Ogrenci{Insan{"Ahmet", 21, "111-222-XXX"}, "ITU", 100}
|
||||
mehmet := Calisan{Insan{"Mehmet", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
||||
veli := Calisan{Insan{"Veli", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
||||
|
||||
// i interface'ini tanımlayalım.
|
||||
var i Adamlar
|
||||
|
||||
//Ogrenci' yi tutabilirm
|
||||
i = ali
|
||||
fmt.Println("Öğrenci the Ali basliyor :D :")
|
||||
i.Merhaba()
|
||||
i.SarkiSoyle("November rain")
|
||||
|
||||
//Calisan ' tutabilirim.
|
||||
i = veli
|
||||
fmt.Println("Veli bir Calisan:")
|
||||
i.Merhaba()
|
||||
i.SarkiSoyle("Uykusuz her gece, yorgun ölesiye!")
|
||||
|
||||
// Adamlar 'dan parçalar/dilimler(slice)
|
||||
fmt.Println("Adamlar' ı dilimlere ayıralım ve n'olacağını görelim.")
|
||||
x := make([]Adamlar, 3)
|
||||
// Bu üç element farklı türdeler fakat hepsi Adamlar interface'ini uyguluyor/implement ediyor.
|
||||
x[0], x[1], x[2] = ali, ahmet, mehmet
|
||||
|
||||
for _, value := range x {
|
||||
value.Merhaba()
|
||||
}
|
||||
}
|
||||
```
|
||||
Interface kendini implement edemez.
|
||||
|
||||
### Boş interface
|
||||
|
||||
Boş interface, herhangi bir method içermeyen bir interface'dir. Bu nedenle tüm type'lar boş bir interface uygular. Bu durum, tüm türleri tek noktada saklamak istediğimizde çok kullanışlıdır ve C'deki void * 'e benzer.
|
||||
```Go
|
||||
// boş interface uygulaması
|
||||
var bos interface{}
|
||||
|
||||
// degiskenler
|
||||
i := 5
|
||||
s := "Selam dünya"
|
||||
|
||||
// herhangi bir türden veri tutabilir.
|
||||
bos = i
|
||||
bos = s
|
||||
```
|
||||
|
||||
Eğer bir fonskiyon değişken türü olarak boş interface kullanıyorsa, herhangi bir türü kabul edebilir; bir fonksiyon dönüş değeri türü olarak boş interface kullanıyorsa, herhangi bir türü döndürebilir.
|
||||
|
||||
### Interface'in method argümanları
|
||||
|
||||
Herhangi bir değişken bir arayüzde kullanılabilir. Peki bu özelliği herhangi bir değişkeni bir fonksiyona geçirmek için nasıl kullanabiliriz?
|
||||
|
||||
Örneğin, fmt.Println'i çok kullanıyoruz, ancak herhangi bir argümanı kabul edebileceğini hiç fark ettiniz mi? "Fmt" nin açık kaynak koduna baktığımızda, aşağıdaki tanımı görüyoruz.
|
||||
|
||||
```Go
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
```
|
||||
Bu, Stringer interface'ini uygulayan herhangi bir türün bağımsız değişken olarak fmt.Println'ye geçirilebileceği anlamına gelir. Kanıtlayalım.
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Insan struct {
|
||||
ad string
|
||||
yas int
|
||||
telefon string
|
||||
}
|
||||
|
||||
// Insan implements fmt.Stringer
|
||||
func (h Insan) String() string {
|
||||
return "ad:" + h.ad + ", yas:" + strconv.Itoa(h.yas) + ", Contact:" + h.telefon
|
||||
}
|
||||
|
||||
func main() {
|
||||
isik := Insan{"Isik", 25, "000-7777-XXX"}
|
||||
fmt.Println("Bu kişi: ", isik)
|
||||
}
|
||||
```
|
||||
|
||||
Asagıdaki box örneğine baktığımızda, Color'ın Stringer interface'ini de uyguladığını göreceksiniz, böylece yazdırma biçimini özelleştirebiliyoruz. Eğer ki bu interface'i uygulamazsak, fmt.Println türü varsayılan biçimiyle yazdırır.
|
||||
```Go
|
||||
fmt.Println("En büyük", boxes.BiggestsColor().String())
|
||||
fmt.Println("En büyük", boxes.BiggestsColor())
|
||||
```
|
||||
Uyarı: Eğer type ` error interface'ini uyguladıysa, fmt `Error () ' olarak adlandırır, bu nedenle bu noktada Stringer uygulamasına gerek kalmaz.
|
||||
|
||||
### Interface' in değişken türü
|
||||
|
||||
Eğer değişken, interface'i uygulayan type'sa aynı interface'i uygulayan başka herhangi bir type'ın bu değişkene atanabileceğini biliyoruz. Soru, interface'de saklanan belirli türü nasıl bilebiliriz?
|
||||
Size göstereceğim iki yol var.
|
||||
|
||||
- Comma-ok pattern
|
||||
|
||||
Go syntax'ına uygun olarak şöyle bir şey yapılabilir `deger, ok := element.(T)`.
|
||||
Değişkenin beklediğimiz tür olup olmadığını kontrol eder; burada "değer", değişkenin değeri, "ok", boolean türünden bir değişkeni, "element" interface değişkeni ve T, yerleştirmenin türüdür .
|
||||
|
||||
Element beklediğimiz türse, "ok" true, değilse false olur.
|
||||
|
||||
Daha iyi anlaşılması için biraz daha örnek verelim.
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Element interface{}
|
||||
type List []Element
|
||||
|
||||
type Person struct {
|
||||
ad string
|
||||
yas int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return "(ad: " + p.ad + " - yas: " + strconv.Itoa(p.yas) + " years)"
|
||||
}
|
||||
|
||||
func main() {
|
||||
list := make(List, 3)
|
||||
list[0] = 1 // an int
|
||||
list[1] = "Hello" // a string
|
||||
list[2] = Person{"Dennis", 70}
|
||||
|
||||
for index, element := range list {
|
||||
if value, ok := element.(int); ok {
|
||||
fmt.Printf("list[%d] 'in türü int and degeri: %d\n", index, value)
|
||||
} else if value, ok := element.(string); ok {
|
||||
fmt.Printf("list[%d] 'in string int and degeri: %s\n", index, value)
|
||||
} else if value, ok := element.(Person); ok {
|
||||
fmt.Printf("list[%d] 'in türü Person and degeri: %s\n", index, value)
|
||||
} else {
|
||||
fmt.Printf("list[%d] 'in bambaşka bir türü var... \n", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
Bu kalıbı/pattern'i kullanmak oldukça kolaydır, ancak test etmek için birçok türümüz varsa, `switch` i kullansak iyi olur.
|
||||
|
||||
- switch test
|
||||
|
||||
Hadi `switch` kullanarak üstteki örneği yeniden yazalım.
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Element interface{}
|
||||
type List []Element
|
||||
|
||||
type Person struct {
|
||||
ad string
|
||||
yas int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return "(ad: " + p.ad + " - yas: " + strconv.Itoa(p.yas) + " years)"
|
||||
}
|
||||
|
||||
func main() {
|
||||
list := make(List, 3)
|
||||
list[0] = 1 //an int
|
||||
list[1] = "Selam" //a string
|
||||
list[2] = Person{"isik", 25}
|
||||
|
||||
for index, element := range list {
|
||||
switch value := element.(type) {
|
||||
case int:
|
||||
fmt.Printf("list[%d] bir int and ve değeri %d\n", index, value)
|
||||
case string:
|
||||
fmt.Printf("list[%d] bir string and ve değeri %s\n", index, value)
|
||||
case Person:
|
||||
fmt.Printf("list[%d] bir Person and ve değeri %s\n", index, value)
|
||||
default:
|
||||
fmt.Println("list[%d] bambaşka bir türe(tyoe) sahip", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Unutmamalıyız ki `element. (Type)`, `switch` gövdesinin dışında kullanılamaz, bu durumda`virgül-ok` desenini kullanmanız gerektiği anlamına gelir.
|
||||
### Embedded interfaces
|
||||
|
||||
Go' daki güzel şeylerden biri de structlardaki anonim alanlar gibi birçok yerleşik mantık sözdizimine sahip olmasıdır. Şaşırtıcı olmayan bir şekilde, interfaceleri anonim alanlar olarak da kullanabiliriz, ancak onlara `Gömülü(embedded) interface` diyoruz. Burada anonim alanlarla aynı kuralları uygularız. Daha spesifik olarak, bir interface'in içinde gömülü başka bir interface varsa, gömülü interface'in sahip olduğu tüm yöntemlere sahipmiş gibi davranacaktır.
|
||||
|
||||
`Container / heap` içindeki kaynak kodların aşağıdaki gibi olduğunu görebiliriz:
|
||||
```Go
|
||||
type Interface interface {
|
||||
sort.Interface // embedded sort.Interface
|
||||
Push(x interface{}) //a Push method to push elements into the heap
|
||||
Pop() interface{} //a Pop method that pops elements from the heap
|
||||
}
|
||||
```
|
||||
`Sort.Interface` öğesinin gömülü bir interface olduğunu görüyoruz, bu nedenle yukarıdaki Interface'de kapalı olarak "sort.Interface" içinde bulunan üç yöntem vardır.
|
||||
|
||||
```Go
|
||||
type Interface interface {
|
||||
Len() int
|
||||
Less(i, j int) bool
|
||||
Swap(i, j int)
|
||||
}
|
||||
```
|
||||
Başka bir örneği de `io` paketi içinde bulunan`io.ReadWriter` 'de görebiliriz.
|
||||
```Go
|
||||
// io.ReadWriter
|
||||
type ReadWriter interface {
|
||||
Reader
|
||||
Writer
|
||||
}
|
||||
```
|
||||
### Reflection(Yansıma)
|
||||
|
||||
Go'daki yansıma, çalışma zamanında bilgileri belirlemek için kullanılır. `reflect` paketini, [Yansıma kuralları](http://golang.org/doc/articles/laws_of_reflection.html) yansımanın nasıl calıstıgına baktıktan sonra göreceğiz.
|
||||
|
||||
Yansıtmayı kullanırken üç adım söz konusudur. İlk olarak, bir interface'i türleri yansıtacak şekilde dönüştürmeliyiz (reflect.Type veya reflect.Value bu duruma bağlıdır).
|
||||
|
||||
```Go
|
||||
t := reflect.TypeOf(i) // i'nin içindeki meta veriyi al ve tüm öğeleri almak için t'yi kullan
|
||||
v := reflect.ValueOf(i) // type i 'nin içindeki gerçek değeri al,ve v' yi değiştirmek için değerini kullan.
|
||||
```
|
||||
Bundan sonra, ihtiyaç duyduğumuz değerleri elde etmek için yansıyan türleri dönüştürebiliriz.
|
||||
|
||||
```Go
|
||||
var x float64 = 3.4
|
||||
|
||||
t := reflect.TypeOf(x)
|
||||
v := reflect.ValueOf(x)
|
||||
|
||||
fmt.Println("type:", t)
|
||||
fmt.Println("value:", v)
|
||||
fmt.Println("kind float64 mu?:", v.Kind() == reflect.Float64)
|
||||
```
|
||||
Son olarak, yansıyan türlerin değerlerini değiştirmek istiyorsak, onu değiştirilebilir yapmamız gerekir. Daha önce tartışıldığı gibi, değere göre geçiş ile referansa göre geçiş arasında bir fark vardır. Aşağıdaki kod derlenmeyecektir.
|
||||
```Go
|
||||
var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)
|
||||
v.SetFloat(7.1)
|
||||
```
|
||||
Bunun yerine, yansıma türlerinden değerleri değiştirmek için aşağıdaki kodu kullanmalıyız.
|
||||
|
||||
```Go
|
||||
var x float64 = 3.4
|
||||
p := reflect.ValueOf(&x)
|
||||
v := p.Elem()
|
||||
v.SetFloat(7.1)
|
||||
```
|
||||
Yansımanın temellerini az önce tartıştık, ancak daha fazlasını anlamak için daha fazla pratik yapmalısınız.
|
||||
|
||||
## Links
|
||||
|
||||
- [Directory](preface.md)
|
||||
- Previous section: [Nesne-Yönelim](02.5.md)
|
||||
- Next section: [Eş-zamanlılık](02.7.md)
|
||||
Reference in New Issue
Block a user