Какво са масивите в Go?
Могат ли да имат променлива дължина?
Какво е range
?
Как са имплементирани слайсовете в Go?
len
) определя този слайс каква част от масива вижда.
arr := [6]float64{1,2,3,4,5,6}
x := arr[1:]
slice1 := append(x, 4)
Какви типове имат arr
, x
, slice1
?
Какво ще върнат len(x)
, cap(x)
, len(slice1)
, cap(slice1)
?
Какво прави този код:
var x map[string]int x["key"] = 10 if name, ok := x["key"]; ok { fmt.Println(name, ok) }
Каква е разликата между new
и make
и кога се ползва едното, и кога другото?
new
само заделя памет и я нулира, за разлика от make
, което инициализира обекта. new
ползваме за наши типове (структури), make
само за слайсове и хешове. new
връща указател, make
връща стойност.type integer int type float float64 type chars string
func Abs(i integer) integer { switch { case i < 0: return -i case i == 0: return 0 default: return i } } var number integer = -42 positiveInteger := Abs(number)
Abs
, която се извиква като ѝ се подаде integer като аргументfunc (i integer) Abs() integer { switch { case i < 0: return -i case i == 0: return 0 default: return i } } var number integer = -42 number.Abs()
* По стойност
- Работи се върху копие на обекта
- Това може да е скъпа операция за големи обекти
* Като указател
- Работи се върху самия обект
- Всяка промяна в метода се отразява на оригиналния обект
package main
import "fmt"
type integer int func (i integer) Abs() integer { switch { case i < 0: return -i case i == 0: return 0 default: return i } } func (i *integer) Increment() { *i++ } func main() { var number integer number = -42 number.Increment() fmt.Println(number.Abs())
}
type Rectangle struct { x, y int } type Triangle struct { x, y, z int }
func (r *Rectangle) Circumference() int { return 2 * (r.x + r.y) } func (r *Triangle) Circumference() int { return r.x + r.y + r.z }
Circumference()
type Shape interface { Circumference() }
Circumference
със същата сигнатура, имплементира Shape
Triangle
и Rectangle
имплицитно го имплементиратpackage main
import "fmt"
type Shape interface {
Circumference() int
}
type Rectangle struct {
x, y int
}
func (r *Rectangle) Circumference() int {
return r.x + r.y
}
type Triangle struct {
x, y, z int
}
func (t *Triangle) Circumference() int {
return t.x + t.y + t.z
}
func sumOfCircumferences(shapes ...Shape) int { sum := 0 for _, shape := range shapes { sum += shape.Circumference() } return sum }
func main() {
rect := &Rectangle{x: 12, y: 64}
tr := &Triangle{x: 12, y: 64, z: 50}
fmt.Println(sumOfCircumferences(rect, tr))
}
Конструираме един тип, комбинирайки няколко прости други типa.
* Пример:
Искаме да си направим smartphone. Не откриваме топлата вода, а просто го наблъскваме с каквито джаджи се сетим.
type Smartphone struct { phone BasicPhone camera CameraModule wifi WiFiModule screen MultiTouchScreen battery DamnHugeBattery }
Всеки един от тези типове отговаря за точно едно нещо и може да бъде използвано самостоятелно.
Вярваме, че знаете как работи то. Дори сме сигурни, че сте правили хора и студенти:
type Student struct { Person facultyNumber int16 }
Вложеният тип, е анонимен, което присвоява всичките му методи и атрибути на базовия клас.
Да, имате право на много анонимни вложени типа. Не го правете.
type Stringer interface { String() string }
Всеки тип, който имплементира този интерфейс, може да бъде принтиран в Printf
например с %s
.
Printf
просто ще извиква String()
и ще вземе стойността.
Всеки обект имплементира празния интерфейс
interface{}
С променлива от такъв тип не можем да правим абсолютно нищо. Това може да звучи безполезно, но не е, ако имаме следното...
var value interface{} value = 20 value = "asd" str := value.(string)
На последния ред или ще се паникьосаме, или в str
ще имаме стойността на value
, ако тя наистина е била от тип string
.
var value interface{} switch str := value.(type) { case string: return str case Stringer: return str.String()
Начин да се държим по различен начин въз основа на типа на нещо.