Как увеличаваме броя елементи в един масив? Можем ли да сравняваме масиви с оператора "=="
?
==
arr := [6]float64{1, 2, 3, 4, 5, 6} x := arr[1:] y := append(x, 4)
Какви типове имат arr
, x
, y
?
Какво ще върнат len(x)
, cap(x)
, len(y)
, cap(y)
?
Кои от следните типове са допустими ключове на map?
string
[5]int
[]int
struct{int}
*[]int
Отговор:
[]int
*[]int
допустим ключ, макар и не много полезен:package main
import (
"fmt"
)
func main() { slice := []int{1, 2, 3} fmt.Printf("%+v\n", map[*[]int]int{&slice: 5}) }
Каква е разликата между new()
и make()
, кога се ползва едното и кога другото и какво връщат?
new
само заделя памет и я нулира, за разлика от make
, което инициализира обектаnew
ползваме за наши типове (структури), а make
за вградени типове като slices и mapsnew
връща указател, make
връща стойностКак инициализираме thread-safe slice или map?
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()
По стойност
Като указател
Няма различен синтаксис за използването на двата вида receiver-и.
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()) }
Извикването на методи работи дори с nil pointers към обекти:
package main
import "fmt"
type integer int func (i *integer) Increment() { fmt.Println("Incrementing...") *i++ } func main() { var number *integer number.Increment() fmt.Println(number) }
Внимавайте с тях :)
type Rectangle struct { X, Y int } type Triangle struct { X, Y, Z int }
func (r *Rectangle) Area() float64 { return float64(r.X * r.Y) } func (r *Rectangle) Circumference() int { return 2 * (r.X + r.Y) } func (t *Triangle) Area() float64 { p := float64(t.Circumference() / 2) return math.Sqrt(p * (p - float64(t.X)) * (p - float64(t.Y)) * (p - float64(t.Z))) } func (t *Triangle) Circumference() int { return t.X + t.Y + t.Z }
package main
import "fmt"
type greeter struct { Name string } func (g *greeter) SayHi(name string) { fmt.Printf("Hi, %s! I am %s (%p)\n", name, g.Name, g) } func main() { var p = &greeter{Name: "p"} pGreeter := p.SayHi fmt.Printf("Calling p.SayHi:\n") p.SayHi("Pesho") fmt.Printf("Calling pGreeter:\n") pGreeter("Pesho") // The same as p.SayHi("Pesho") unboundGreeter := (*greeter).SayHi fmt.Printf("Calling unboundGreeter:\n") unboundGreeter(p, "Gosho") unboundGreeter(&greeter{Name: "other"}, "Maria") }
Circumference()
и Area()
type Stringer interface { String() string }
Това е интерфейс от стандартната библиотека, дефиниран в пакета fmt
.
Ако имплементираме този интефейс за наш тип, може да променим начина, по който fmt.Printf()
го принтира чрез %s
.
package main
import (
"fmt"
"strconv"
)
type myint uint64 func (i myint) String() string { return "myint in binary is " + strconv.FormatUint(uint64(i), 2) } func main() { var i myint i = 5 fmt.Printf("Value: %s\n", i) }
type Binary uint64
По-подробно обяснение може да намерите тук: research.swtch.com/interfaces
type Shape interface { Area() float64 Circumference() int }
Circumference
и Area
със същата сигнатура, имплементира Shape
Triangle
и Rectangle
имплицитно го имплементиратpackage main
import (
"fmt"
"math"
)
// start interface OMIT
type Shape interface {
Area() float64
Circumference() int
}
// end interface OMIT
// start types OMIT
type Rectangle struct {
X, Y int
}
type Triangle struct {
X, Y, Z int
}
// end types OMIT
// start methods OMIT
func (r *Rectangle) Area() float64 {
return float64(r.X * r.Y)
}
func (r *Rectangle) Circumference() int {
return 2 * (r.X + r.Y)
}
func (t *Triangle) Area() float64 {
p := float64(t.Circumference() / 2)
return math.Sqrt(p * (p - float64(t.X)) * (p - float64(t.Y)) * (p - float64(t.Z)))
}
func (t *Triangle) Circumference() int {
return t.X + t.Y + t.Z
}
// end methods OMIT
func sumOfCircumferences(shapes ...Shape) int { sum := 0 for _, shape := range shapes { sum += shape.Circumference() } return sum } func biggestArea(shapes ...Shape) (result float64) { for _, shape := range shapes { area := shape.Area() if area > result { result = area } } return result } func main() { rect := &Rectangle{X: 12, Y: 64} tr := &Triangle{X: 12, Y: 64, Z: 50} fmt.Println(sumOfCircumferences(rect, tr)) fmt.Println(biggestArea(rect, tr)) }
Конструираме един тип, комбинирайки няколко прости други типa.
* Пример:
Искаме да си направим smartphone. Не откриваме топлата вода, а просто го наблъскваме с каквито джаджи се сетим.
type Smartphone struct { phone BasicPhone camera CameraModule wifi WiFiModule screen MultiTouchScreen battery DamnHugeBattery gyroscope SmallGyroscope gps GPSModule secret CanOpener }
Всеки един от тези типове отговаря за точно едно нещо и може да бъде използвано самостоятелно.
Вярваме, че знаете как работи то. Дори сме сигурни, че сте правили хора и студенти:
package main
import "fmt"
type Person struct { firstName, lastName string } func (p Person) Name() string { return p.firstName + " " + p.lastName } type Student struct { Person facultyNumber int16 } func main() { s := Student{Person{"Иван", "Иванов"}, 123} fmt.Printf("We have a student with name %s and FN %d", s.Name(), s.facultyNumber) }
Вложеният тип Person е анонимен, което присвоява всичките му методи и атрибути на базовия тип.
Да, имате право на много анонимни вложени типа.
Не, това не е яко.
Да, не очакваме да го ползвате често.
Всеки обект имплементира празния интерфейс:
interface{}
Съответно на променлива от такъв тип може да присвоим всякаква стойност!
Но с нея не можем да правим абсолютно нищо :)
Това може да звучи безполезно, но не е, тъй като имаме...
package main import "fmt" func main() { var value interface{} value = 20 value = "asd" if str, ok := value.(string); ok { fmt.Printf("We have a %T: %v\n", str, str) } else { fmt.Println("Oops, not a string") } }
В str
ще имаме стойността на value
, ако тя наистина е била от тип string
.
package main
import "fmt"
type mystruct struct{ a, b int } func (m mystruct) String() string { return fmt.Sprintf("mystruct(%d, %d) yo!", m.a, m.b) } func stringify(value interface{}) string { switch s := value.(type) { case string: return s case fmt.Stringer: return s.String() case int, uint: return fmt.Sprintf("%06d", s) // leftpad default: return "No clue, mate :)" } } func main() { fmt.Printf("%#v\n", stringify(mystruct{1, 2})) }
Така може да правим различни неща въз основа на типа на променлива.
package main
import (
"encoding/json"
"fmt"
)
type Rectangle struct { X, Y int } func main() { var empty interface{} emptyRect := new(Rectangle) rect := &Rectangle{X: 12, Y: 64} marshalledRect, _ := json.Marshal(rect) fmt.Printf("%s\n", marshalledRect) json.Unmarshal(marshalledRect, emptyRect) fmt.Printf("%#v\n", emptyRect) json.Unmarshal(marshalledRect, &empty) fmt.Printf("%#v\n", empty) }
type Marshaler interface { MarshalJSON() ([]byte, error) } type Unmarshaler interface { UnmarshalJSON([]byte) error }
package main
import (
"encoding/json"
"fmt"
)
type Triangle struct {
X, Y, Z int
}
func (t *Triangle) MarshalJSON() ([]byte, error) { return json.Marshal(struct { X, Y, Z int Shape string }{ X: t.X, Y: t.Y, Z: t.Z, Shape: "Триъгълник", }) } func main() { tr := &Triangle{X: 12, Y: 64, Z: 50} marshalledTr, _ := json.Marshal(tr) fmt.Printf("%s\n", marshalledTr) }
type integerAlias = int
Не създава нов тип, a псевдоним на вече съществуващ тип
package main
type integer int func isPositive(a integer) bool { return a > 0 } type integerAlias = int func isPositive1(a integerAlias) bool { return a > 0 } func main() { a := 5 isPositive(a) // cannot use a (type int) as type integer in argument to isPositive isPositive1(a) }