Go Üzerine

Nasıl Ortaya Çıktı ?

Go programlama dili, Google tarafından 2007 yılından itibaren açık kaynak kodlu olarak Robert Griesemer, Ken Thompson ve Rob Pike tarafından başlatılan bir projedir. 2008 yılında Ian Lance Taylor ve Russ Cox bu projeye dahil oldular. Kasım 2009’da projenin varlığını bildirdiler. Go’nun ilk versiyonu Mart 2012’de yayınlanmıştır. 2015 yılından itibaren akıllı telefonlar için kullanılmaya başlanmıştır.

Thompson Amerikalı bir bilgisayar bilimcisidir. Thompson, Unix işletim sistemini tasarlayıp uyguladığı Bell Labs’ta çalıştı. 2006’dan beri Go programlama dilini birlikte icat ettiği Google’da çalışıyor.

Griesemer, İsviçreli bir bilgisayar bilimcisidir. Zürih Federal Teknoloji Enstitüsü olarak da bilinen, İsviçre’nin Zürih kentinde kurulu üniversitede lisansını ve doktorasını tamamladı.

Pike, Kanadalı bir programcı ve yazardır. Go programlama dili ve Unix ekibinin bir üyesi olduğu Bell Labs’daki çalışmaları ile tanınır.

Go aslında deney amaçlı ortaya çıktı. Amaç; diğer dillerin iyi özelliklerini korumak, ancak eleştiri alan kısımlarına çözüm üretmek üzere geliştirilmeye başlandı. Yaratıcıları ile yapılan görüşmelerde o zamanlarda çoğunlukla kullanılan C++ programlama dilinin sorunlarına çözüm olacak bir proje başlattıklarını söylenmiştir. Go projesi başlamadan önce Google, kendi projelerinde C, Java, C++, Python vs. bir çok yazılım dilini kullanıyorlardı. Performans sorunlarını o dilin yetebildiği oranda çözmeye çalıştılar. Kodun derlenme sürelerinin uzun olması, yaşanan performans problemleri, güvenlik zaafiyetleri, zaman yönetimi, daha iyi performans için daha fazla kaynak alımının artması Google ve 3 mühendisin Go deneysel projeyi ortaya çıkarmasını sağladı.

Go takımı ile tanışmak isteseniz https://www.youtube.com/watch?v=sln-gJaURzk linkindeki videoyu izleyebilirsiniz.

Go’nun Genel Yapısı Nasıldır ?

Dilin anlaşılır ve basit bir yapısı var. Dilde sadece 25 anahtar (keyword) bulunuyor.
C dilinde 37, C++ dilinde 84, Java dilinde 52, Python dilinde 33 anahtar mevcut.

Tanımlama (Declaration)

const, var, type, func , import , package

Kompozit Tipler (Composite Types)

chan, map, interface, struct

Kontrol

break, continue, case ,default, fallthrough, for, if, goto, return, select, switch, else, range

Fonksiyon

go, defer2

Tipler ve bazı “built-in” fonksiyonlar

append, bool, byte, cap, close, complex, complex64, complex128, uint16, copy, false, float32, float64, imag, int, int8, int16, uint32, int32, int64, iota, len, make, new, nil, panic, uint64, print, println, real, recover, string, true, uint, uint8, uintptr

Go dilini incelediğimizde jenerik bir yapıya sahip olmadığını görürüz. Jenerikler elbette kullanışlıdır. Ancak çalışma zamanının yarattığı karmaşıklık açısından bir maliyete sahip olacaktır. Geliştirici ekibinin elbetteki amacı bu değildi. Basitlik ve performans göz önünde bulundurularak tasarlanmıştı.

İlk Go kodunu yazdığınızda farkedeceğiniz, derlenme süresinin ne kadar hızlı olduğudur. Go Garbage Collector (Belleği Boşaltma İşlemi) mimarisine sahiptir. Hafıza (Memory) yönetimi Go tarafından sağlanır. Güçlü standart kütüphane yönetimine sahiptir.

Açık Kaynak Kodlu, Cross-Platform

Go tamamen açık kaynak kodludur. Go kaynak kodunu tümüyle inceleyebilirsiniz. Kaynak kodu Github üzerinde https://github.com/golang linkinden bulabilirsiniz.

OpenBSD, NetBSD, FreeBSD, Windows, Linux, MacOS, AIX, Android, Darwin, Dragonfly, Hurd, Illumos, Js, Nacl, Plan9, Solaris, Zos tarafından desteklenmektedir.

Go yaratıcılarının katkılarının yanı sıra, piyasada Go dilini kullanan büyük teknoloji firmalarının da Go’nun gelişimine katkıda bulunduğunu söyleyebiliriz.

Go’ya Eklenmemiş Yapılar Nelerdir?

Diğer programlama dillerinde olan bazı özellikler hız ve basitlik olması açısından Go’ya eklenmemiştir. Kalıtım (Inheritance), Method Aşırı Yükleme (Overloading), Jenerik Programlama, Çok Biçimlilik (Polymorphism) özellikleri Go’da yoktur.

Bknz: https://golang.org/doc/faq#generics

Go Map Operasyonları Neden Atomic Değil?

Go yaratıcıları map kullanımlarını güvensiz erişim şeklinde bırakıp bırakmamak konusunda uzun süre tartışmışlar. Yazının başında dediğim gibi hız, düşük maliyet Go’nun vizyonudur. Map’leri çoklu erişimlerde güvensiz bırakmışlar. Bu şekilde daha büyük veri yapılarında daha hızlı arama ve hesaplamalar yapılabilecektir.

Go Object-OrIented Bir Programlama Dili Midir?

Aslında bu sorunun cevabı yok. Hem evet hem hayır. Go’da yer alan tipler, methodlar, fonksiyonlar Object-Oriented Programlama dilinin bazı özelliklerini taşıyor. Go’da “object” olarak nitelendirilen bir yapı yok. Bunun yerine değişken tanımlarının ve methodların yer aldığı “struct” yapısı bulunuyor.

Go Neye Benziyor?

Bu konuda herkesin bir fikri olabilir. Ancak Go geliştiricileri bu konuda net bir açıklama yapmışlar. Söz dizimi (syntax) olarak çoğunlukla “C” dilinin yapısına benziyor. Tanımlama ve paket düzeni olarak Pascal/Modula/Oberon ailesinden alıntılar mevcut. Eş zamanlılık (concurrency) olarak Limbo diline benzerlik gösteriyor.

Bkz: https://golang.org/doc/faq#ancestors

Go’yu dünyada kullanan Firmalar Neler?

Bazı Yabancı Teknoloji Firmaları:

Docker
Koding
Dailymotion
SendGrid
SoundCloud
Dropbox
Medium
Google
Ubuntu
Uber
Twitch
Facebook

Bazı Yerli Teknoloji Firmaları:

put.io
LocRep
Optimum Yazılım
Mentornity, Inc.
Insider
Admongrel
Frigbo
Trendyol.com
Peak Games
Metglobal
MasomoGaming
Mos Teknoloji

Daha kapsamlı bilgiyi https://github.com/golang/go/wiki/GoUsers sayfasından edinebilirsiniz.

Go Üzerine Basit Örnekler

Yazının başında söylediğim gibi Go dili toplamda 25 anahtara sahip. Şimdi her bir anahtardan kod örnekleri vereceğim.

import

Go üzerinde herhangi bir referans göstermeden kullanılabilecek fonksiyonlar mevcuttur. Go’da “import” anahtar kelimesi ile kütüphaneleri referans gösterebiliriz. Paketler içerisinde yer alan tüm fonksiyonlar erişilebilir ve kullanılabilir hale gelir. Println() fonksiyonu ekrana girdiyi yazdırmak için kullanılır. Ancak bu fonksiyonu kullanabilmek için “fmt” paketinin import edilmesi gerekir.

package main
import (
	"fmt"
)
func main() {
	fmt.Println("I learn Go!")
}
struct

Object-Oriented programlama dillerindeki “object” anahtarına benzer bir yapısı vardır. Go’da Sınıf’a (Class) Struct diyebilirsiniz.

package main
import (
	"fmt"
	"strconv"
)

type Person struct {
   Name string
   Address string
   Phone string
   Age int
}

func main() {
	var person *Person
	person = &Person{Name:"Parta",Address:"IZMIR",Phone:"02322908811",Age:14}
	fmt.Println("My Name is",person.Name,".I am at",person.Address,".My phone number is",person.Phone,"I am",strconv.Itoa(person.Age),"years old.")	
}
const

Go’da statik tanımlamalar “const” anahtar kelimesi ile yapılabilmektedir. Gerek globalde gerekse lokal olarak const tanımı yapılabilir.

package main

import "fmt"

const (
    Name  		= "Parta"
    Sector 		= "Software"
    Age  		= 14
    BirthYear 	= 2006
)
const (
    First = 5 * iota
    Second
    Third
)
func main() {
	fmt.Println(Name)
	const localnumber = 1881
	fmt.Println(localnumber)
	const a = "50"
	fmt.Println(a)
	fmt.Println(First)
	fmt.Println(Second)
	fmt.Println(Third)
}
Çıktı:

Parta
1881
50
0
5
10
var

Go’da değişken tanımları yapılırken herhangi bir değişken tipi belirtme zorunluluğu yoktur. Değişken tipi belirtileceği zaman “var” anahtar kelimesini kullanıyoruz.

package main

import "fmt"

func main() {
	var a, b int = 1, 2
	c:="3"
	d:=4
	e, f, g, h := true, false, 4.5,"yes"
	fmt.Println(a, b, c, d, e, f, g, h)
}
Çıktı:

1 2 3 4 true false 4.5 yes
type

package main
import "fmt"

type Food interface {
    Cook() bool
    Mix() bool
    Eat() bool
}

type Meat struct {
	name string
    cookTime int
}

func (m Meat) Cook() bool {
    fmt.Printf("Food %s is started. It will be finished after %d seconds.\n",m.name,m.cookTime)
    return true
}

func (m Meat) Mix() bool {
    fmt.Printf("Food %s is being mixed.\n",m.name)
    return true
}

func (m Meat) Eat() bool{
	fmt.Printf("Food %s started to be eaten.\n",m.name)
	return true
}

func main() {
	var m *Meat
	m = &Meat{name:"Meatball",cookTime:100}
	m.Cook()
	m.Mix()
	m.Eat()
	fmt.Println("All is ok!")
}
Çıktı: 

Food Meatball is started. It will be finished after 100 seconds.
Food Meatball is being mixed.
Food Meatball started to be eaten.
All is ok!
func

Go’da fonksiyon tanımlamaları “func” anahtar kelimesi ile başlar.

package main

import "fmt"
// A function that sum all elements in array
func Sum(numbers []int) int{
	count:=0
	for _,cnt :=range numbers {
		count += cnt
	}
	return count
}

func main() {
	var elements = []int{1,2,3,4,5}
	fmt.Println(Sum(elements))
}
Çıktı:

15
package

Go yazılımcıları tarafından oluşturulmuş paketler import edilerek kullanılabilir.
“main” paketi çalıştırılabilir bir binary program yapmak için kullanılır.

package main
import (
	"strings"
	"github.com/google/gopacket"
	"fmt"
)

chan

Go’da eş zamanlılık mimarisi gerçekten çok iyi işlenmiş. Aynı anda birden fazla işlem sinyalizasyon ile gerçekleştirilebilir.
“chan1 := make(chan int)” ile kanal oluşturulur.
“x:= <-chan1” ile veri alınır. Ok işareti verinin yönünü göstermektedir. “c <- count” ile veri kanala gönderilir. Aşağıda görüleceği üzere sum fonksiyonunda return kullanılmamış, count değeri bir kanala gönderilmiştir.

package main

import "fmt"
// Function that sum of all integer array elements
func sum(numbers []int, c chan int) {
	count := 0
	for _, numb := range numbers {
		count += numb
	}
	c <- count
}

func main() {
	s := []int{1,2,3,4,5,6}
	t := []int{10,20,30,40,50,60}
	chan1 := make(chan int)
	chan2 := make(chan int)
	go sum(s, chan1)
	go sum(t, chan2)
	x:= <-chan1
	y:= <-chan2
	fmt.Println(x,y)
}
Çıktı:

21 210
map

map, aslında key-value şeklinde verilerin tutulmasını sağlayan bir veri yapısı gibi düşünebiliriz. “make” fonksiyonu ile oluşturulur. map değişkeni oluşturulurken herhangi bir büyüklük belirtmeye gerek yoktur. Veri eklendikçe otomatik olarak büyür. Eklendiği sırada bir sıralama oluşturmaz. İlgili map değişkenini bir döngüde verileri yazdırmak istediğinizde, her defasında farklı bir sırada olduğunu gözlemlersiniz.

Verinin fazla olduğu map array’lerinde, arama çok hızlı yapılabilmektedir. Bunun nedeni Go tasarımcılarının map’i unsafe olarak bırakmalarıdır. Oluşturulan global bir map’e aynı anda birden fazla mikro servisin yazma işlemi sırasında programınız crash olabilir. Mutex ile bu sorunu çözmeniz gerekecektir. Ancak aynı anda erişim söz konusu olmadığında mutex’e gerek yoktur. Dolayısıyla daha hızlı bir erişim sağlar.

package main

import "fmt"

type People struct {
	IdentityNu  string
	Sex 	    string
	Nationality string
	Likes 		[]string
}

var w map[string]*People

func main() {
	w= make(map[string]*People)
	w["PartaNetworks"] = &People{IdentityNu:"11111111111",Sex:"man",Nationality:"Turkey",Likes:[]string{"Football","Basketball","Chess"}}
	fmt.Println(w["PartaNetworks"].IdentityNu)
	fmt.Println(w["PartaNetworks"].Sex)
	fmt.Println(w["PartaNetworks"].Nationality)
	fmt.Println(w["PartaNetworks"].Likes)
}
Çıktı: 

11111111111
man
Turkey
[Football Basketball Chess]

interface

Go jenerik (generics) değildir. Eğer Object-Oriented bir programalama dili kullandıysanız jenerik yapılara hakimsinizdir. Jenerik yapılar olmadığında type yazımı biraz sizi zorlayabilir. Bu durumu interface{} ile biraz da olsa aşabilirsiniz.

package main
import "fmt"

type Food interface {
    Cook() bool
    Mix() bool
    Eat() bool
}

type Meat struct {
	name string
    cookTime int
}

func (m Meat) Cook() bool {
    fmt.Printf("Food %s is started. It will be finished after %d seconds.\n",m.name,m.cookTime)
    return true
}

func (m Meat) Mix() bool {
    fmt.Printf("Food %s is being mixed.\n",m.name)
    return true
}

func (m Meat) Eat() bool{
	fmt.Printf("Food %s started to be eaten.\n",m.name)
	return true
}

func main() {
	var m *Meat
	m = &Meat{name:"Meatball",cookTime:100}
	m.Cook()
	m.Mix()
	m.Eat()
	fmt.Println("All is ok!")
}
Çıktı:

Food Meatball is started. It will be finished after 100 seconds.
Food Meatball is being mixed.
Food Meatball started to be eaten.
All is ok!
break

“break” devam eden işleyişi durdurur. Eğer döngü içerisinde belirtilmiş ise döngüden çıkış yapar. Switch/case yapısında belirtilmiş ise ilgili durumdan(case) çıkış yapar.

package main

import "fmt"

func main() {
	var words = []string{"TR","EN","EU","GR"}
	for _, word := range words {
		if(word=="TR"){
			fmt.Println("Word "+word+" found.")
			break
		}
	}
}
Çıktı:

Word TR found.
continue

Bir loop içerisinde tanımlandığında “continue” satırının akabinde gelen satırlar çalıştırılmaz. Döngüye bir sonraki değerden devam ederek çalışır.

package main

import "fmt"

func main() {
	var words = []string{"TR","EN","EU","GR"}
	for _, word := range words {
		if(word!="TR"){
			continue
		}
		fmt.Println("Word "+word+" found.")
	}
}
Çıktı:

Word TR found.

switch/case/fallthrough/default/select

package main

import (
	"fmt"
	"time"
)
 
func main() {
	today := time.Now()
	switch today.Day() {
	case 5:
		fmt.Println("Watch the film.")
		break
	case 10:
		fmt.Println("Go to the gym.")
		fallthrough
	case 15:
		fmt.Println("Watch the football match")
		break
	case 25:
		fmt.Println("Eat some fruit.")
		break
	default:
		fmt.Println("No information for this day.")
	}
}
Çıktı:

Go to the gym.
Watch the football match

for/range

Aynı diğer dillerde olduğu gibi döngü için “for” anahtarını kullanırız. Döngü için while gibi bir seçenek yok. “for” ile her çeşit döngüyü oluşturabilirsiniz.

package main

import "fmt"

type People struct {
	IdentityNu  string
	Sex 	    string
	Nationality string
	Likes 		[]string
}

var w map[string]*People

func main() {
	w= make(map[string]*People)
	w["Jack"] = &People{IdentityNu:"11111111111",Sex:"man",Nationality:"Turkey",Likes:[]string{"Football","Basketball","Chess"}}
	w["Joe"] = &People{IdentityNu:"2222222222",Sex:"man",Nationality:"England",Likes:[]string{"Football","Swimming","Chess"}}
	for name, p := range w{
		fmt.Println(name+" is a "+p.Sex)
	}
}
Çıktı:

Jack is a man
Joe is a man
if/else

Koşula göre seçim yapar. “if” koşulu desteklerse ilgili alana, desteklemezse “else” kısmındaki koda girer.

package main

import (
	"fmt"
)

func main() {
	var number = 56
	if number%2 == 0 {
        fmt.Printf("%d is even",number)
    } else {
        fmt.Printf("%d is odd",number)
    }
}
Çıktı:

56 is even
goto

goto anahtarının kullanımının faydası konusunda pek çok tartışma olmuştur. Zamanla Yüksek Seviyeli Dillerden (High Level Programming Language) uzaklaştıkça GOTO kullanımının kodu karmaşıklaştırdığı ve sonrasında da spagetti koda sebep olduğu düşünülüyor (Bkz: https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf).

goto ilk olarak Assembly (Makine Kodu) de karşımıza çıkmaktadır. goto yerine kullanılabilecek pek çok anahtar vardır.

package main

import "fmt"

func main() {
   var numb int = 90
   LOOP: for numb < 100 {
      if numb == 15 {
         numb = numb + 1
         goto LOOP
      }
      fmt.Printf("value of number: %d\n", numb)
      numb++     
   }  
}
Çıktı:

value of number: 90
value of number: 91
value of number: 92
value of number: 93
value of number: 94
value of number: 95
value of number: 96
value of number: 97
value of number: 98
value of number: 99

return

İşleyişin devam ettiği durumdan çıkış yapmak için kullanılan bir anahtar kelimedir. Bir fonksiyondan değer döndürmek için kullanılır.

package main

import (
	"fmt"
	"strings"
)
// A function that sum all elements in array
func Search(searchstr string) ([]string,bool){
	var foundTeams []string
	var found bool
	for _,team :=range teams {
		if(strings.HasPrefix(team,searchstr)){
			foundTeams=append(foundTeams,team)
			found = true
		}
	}
	return foundTeams,found
}
var teams = []string{"Real Madrid","Real Zaragoza","Barcelona"}
func main() {
	foundStr,foundBool:=Search("Real")
	fmt.Println(foundStr)
	fmt.Println(foundBool)
}
Çıktı:

[Real Madrid Real Zaragoza]
true
go

Eşzamanlılık, birbirinden bağımsız çalışmaların bir araya gelmesi ve kullanılmasıdır. Paralellik ile çoğu zaman karıştırılır. Metotlar/Fonksiyonlar, “go” kelimesi ile işleyişten bağımsız olarak çalışmaya devam eder. goroutine kesinlikle bir thread değildir.

Eşzamanlılık, bir paralellik değildir.

package main

import (
	"fmt"
	"time"
)

func routine(from string) {
	for i := 0; i < 3; i++ {
		fmt.Println(from, i)
	}
}

func main() {
	routine("call direct")
	go routine("call goroutine")
	go func(msg string) {
		fmt.Println(msg)
	}("going")
	time.Sleep(time.Second)
	fmt.Println("done")
}
Çıktı:

call direct 0
call direct 1
call direct 2
call goroutine 0
call goroutine 1
going
call goroutine 2
done

defer

Kendisini çevreleyen fonksiyon tamamen bitene kadar defer satırında çağırılan fonksiyonun çalışmasını erteler.

package main

import (
	"fmt"
	"os"
)

var f *os.File

func main() {
	f = Create("/tmp/defer.txt")
	defer Close()
	Write()
}

func Create(p string) *os.File {
	fmt.Println("creating")
	f, err := os.Create(p)
	if err != nil {
		panic(err)
	}
	return f
}

func Write() {
	fmt.Println("writing")
	fmt.Fprintln(f, "data")
}

func Close() {
	fmt.Println("closing")
	err := f.Close()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}
Çıktı:

creating
writing
closing

GOPHER

Go projesine başlandığında ikonik bir maskot ya da logoya ihtiyaç vardı. Renee French bunu çizmek için gönüllü oldu. 2009 yılındaki lansman sırasında “Gopher” yani yer sincabı maskot olarak gösterilmesini önerdi. Ve “Go Gopher” doğmuş oldu. Tüm “Gopher” çizimlerini https://golang.org/doc/gopher/ sayfasından erişebilirsiniz.

Go Dünyada Nerede ?

Kaynak: https://www.computer.org/publications/tech-news/trends/programming-languages-you-should-learn-in-2020/


Kaynak: https://flyaps.com/blog/top-10-coding-languages-used-by-global-companies/

KAYNAKLAR:

https://golang.org/

https://9p.io/sources/contrib/ericvh/go-plan9/doc/go_talk-20091030.pdf

https://venkatarangan.com/blog/2020/07/the-top-programming-languages-in-2020-by-ieee-spectrum/

https://flyaps.com/blog/top-10-coding-languages-used-by-global-companies/

Utku KIYAK
Utku KIYAK

Senior IP Software Developer

%d blogcu bunu beğendi: