Skip to content

Latest commit

 

History

History
249 lines (181 loc) · 5.25 KB

08-map.md

File metadata and controls

249 lines (181 loc) · 5.25 KB

Bölüm 04/08: Veri Tipleri

https://go.dev/blog/maps

Map

key=value çiftleri şeklinde içinde veri tuttuğumuz, key ekleme, çıkartma ve silme yapabildiğimiz bir veri tipidir. Python’daki dict ya da Ruby’deki Hash ya da Php’deki Associative Array gibi düşünülebilir. Key üzerinden value’ya ulaşmak O(1) karmaşıklığındadır (complexity) yani çok hızlıdır.

  • Hash table algoritmasını kullanır.
  • Ekleme, çıkartma (silme), okuma O(1) karmaşıklığındadır. Sadece ekleme işlemi amortized karmaşıklık algoritması kullanır.
  • Key/Value çiftleri sıralanmadan (un-ordered) şekilde tutulur
  • Key’ler eşsizdir (unique), bir map’te aynı key’den sadece bir tane olur
  • make fonksiyonu ile map literal (map kalıbı) üretilir, hafızaya yerleştirilir, initialize olur
  • map’lerin initialize değeri nil olur, nil olan map’e key eklenemez!
  • len bize key/value çiftinin uzunluğunu verir
  • map nil mi diye bakılabilir
  • map’leri birbiriyle kıyaslamak için reflection.DeepEqual fonksiyonu kullanılır.

https://go.dev/play/p/X7zOWsYTuyA

package main

import "fmt"

var m map[string]int // nil map, key’i string, value’su int...

func main() {
	fmt.Println(m, len(m)) // map[] 0
	// m["foo"] = 5 // panic: assignment to entry in nil map

	m = make(map[string]int)
	m["foo"] = 5
	fmt.Println(m, len(m)) // map[foo:5] 1
}

map alan fonksiyona nil geçebiliriz, key var mı? yok mu ? bakabiliriz:

https://go.dev/play/p/difVbLWsdCr

package main

import "fmt"

type myMap map[string]string // key: string, value: string

func printMap(m myMap) {
	fmt.Printf("%+v\n", m)
}

func main() {
	printMap(nil) // map[]

	m := myMap{
		"username": "vigo",
	}

	printMap(m)                // map[username:vigo]
	fmt.Println(m["username"]) // vigo
	fmt.Println(m["foo"])      //

	val, ok := m["foo"]
	fmt.Println("ok", ok)   // ok false
	fmt.Println("val", val) // val
}

Ekleme, çıkarma ve hatalı işlemler örneği:

https://go.dev/play/p/YhkzsWMBGBI

package main

import "fmt"

func main() {
	m1 := map[string]int{
		"ocak":  1,
		"şubat": 2,
	}

	var m2 map[string]int
	m2 = make(map[string]int)
	m2["ocak"] = 1
	m2["şubat"] = 2

	fmt.Println(m1) // map[ocak:1 şubat:2]
	fmt.Println(m2) // map[ocak:1 şubat:2]

	// fmt.Println(m1 == m2)
	// error:
	// invalid operation: m1 == m2 (map can only be compared to nil)

	m1["mart"] = 3
	m2["mart"] = 3

	fmt.Println(m1) // map[mart:3 ocak:1 şubat:2]
	fmt.Println(m2) // map[mart:3 ocak:1 şubat:2]

	delete(m1, "mart") // mart key'ini sil
	fmt.Println(m1)    // map[ocak:1 şubat:2]

	for k, v := range m2 {
		fmt.Println("key", k, "->", v)
	}
	// key ocak -> 1
	// key şubat -> 2
	// key mart -> 3

	// m1["mart"] = "ok"
	// error
	// cannot use "ok" (untyped string constant) as int value in assignment

	// m1[1] = "ocak"
	// error
	// cannot use 1 (untyped int constant) as string value in map index
	// cannot use "ocak" (untyped string constant) as int value in assignment
}

Aynı Array ve Slice’daki gibi kapasite kavramı map içinde var;

https://go.dev/play/p/7azH9ymAbvS

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	m1 := make(map[string]int, 10) // Preallocate, 10 tane yer ayır
	fmt.Printf("%#v\n", m1)        // map[string]int{}

	fmt.Println(len(m1))           // 0
	fmt.Println(unsafe.Sizeof(m1)) // 8 byte

	m2 := make(map[string]int)
	fmt.Println(unsafe.Sizeof(m2)) // 8 byte
}

Karşılaştırma;

https://go.dev/play/p/_XIw23G6bPq

package main

import (
	"fmt"
	"reflect"
)

func main() {
	m1 := make(map[string]int, 10) // Preallocate, 10 tane yer ayır
	m2 := make(map[string]int)

	m1["foo"] = 1
	m2["foo"] = 1

	fmt.Println(m1 == nil) // false
	fmt.Println(m2 == nil) // false

	fmt.Println(reflect.DeepEqual(m1, m2)) // true
}

map otomatik olarak referans tipindedir (by ref) aynı pointer ve slice’lar gibi:

https://go.dev/play/p/VZz6a3Sn_QE

package main

import "fmt"

type myMap map[string]string

func modifyMap(m myMap) {
	m["foo"] = "modified"
}

func main() {
	var m myMap
	m = make(myMap)
	m["foo"] = "bar"

	fmt.Printf("initial: %v, memory: %[1]p\n", m)
	// initial: map[foo:bar], memory: 0x14000074180

	fmt.Println("foo:", m["foo"])
	// foo: bar
	modifyMap(m)

	fmt.Printf("modified: %v, memory: %[1]p\n", m)
	// modified: map[foo:modified], memory: 0x14000074180

	fmt.Println("foo:", m["foo"])
	// foo: modified
}

Bazen map’in sadece key kısmı bize lazım olur, value ile işimiz yoktur. Bu durumda value yerine öyle bir şey koymalıyız ki 0 byte yer kaplasın? Bu durumda empty struct tam da aradığımız şeydir:

https://go.dev/play/p/EUmDBlchY5b

package main

import "fmt"

func main() {
	// elimizde 100_000 tane isim var
	// acaba dışarıdan gelen isim bizimde var mı?
	m := map[string]struct{}{
		"uğur":  {},
		"erhan": {},
		"turbo": {},
		"vigo":  {},
	}

	fmt.Println(m)
	// map[erhan:{} turbo:{} uğur:{} vigo:{}]

	// uğur var mı?
	if _, ok := m["uğur"]; ok {
		fmt.Println("uğur tanıdığımız biri")
		// uğur tanıdığımız biri
	}
}