• Go tutorial 笔记


    1 variables

    1.1 string

    var name string = "hello"
    
    • 1

    or:

    var name string
    name = "hello"
    
    • 1
    • 2

    Both are ok.

    1.2 int

    var number uint16 = 260
    
    • 1

    Here uint16 is optional, we can and we should specify the data type, but we don’t have to.

    // let golang implicitly define the data type of the number
    // let golang guess the type based on 260 instead
    var number = 260
    
    • 1
    • 2
    • 3

    ftm.Printf like ‘print format’

    var number = 9999999999999999
    // go guessed type is: int
    fmt.Printf("%T", number)
    
    • 1
    • 2
    • 3

    and

    var number = 9999999999999999.1
    // go guessed type is: float64
    fmt.Printf("%T", number)
    
    • 1
    • 2
    • 3

    1.3 walrus operator :=

    Using walrus operator is the easiest and fastest way to declare a variable.

    // the var keyword is omitted
    // let golang guess the data type
    // shortcut of
    // var number int = 6
    number := 6
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.4 default value

    func main() {
      // false
      var bl bool;
      fmt.Println(bl)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    and:

    func main() {
      // 0
      var d float64;
      f mt.Println(d)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2 fmt, printf, sprintf

    // Hello int 10
    fmt.Printf("Hello %T %v", 10, 10)
    
    • 1
    • 2

    %g will print the FLOAT as it is, but not for integer.

    bool:                    %t
    int, int8 etc.:          %d
    uint, uint8 etc.:        %d, %#x if printed with %#v
    float32, complex64, etc: %g
    string:                  %s
    chan:                    %p
    pointer:                 %p
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // Number: 10000000001
    fmt.Printf("Number: %b", 1025);
    
    • 1
    • 2

    %X for capital letter in hexidecimal

    5 console input (bufio scanner) & type conversion

    import (
    	"bufio"
    	"fmt"
    	"os"
    	// strconv
    )
    
    func main() {
    	scanner := bufio.NewScanner(os.Stdin)
    	fmt.Printf("Type the year you were born: ")
    	scanner.Scan() // always get a string here
    	input := scanner.Text()
    	fmt.Printf("You typed: %q", input)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    run the code above:

    Type something: hello
    You typed: "hello"
    
    • 1
    • 2

    scanner.Scan() always get a string, so if a number is needed, the package strconv must be used.
    The following code to calculate the age at the end of 2020 based on input:

    import (
    	"bufio"
    	"fmt"
    	"os"
    	"strconv"
    )
    
    func main() {
    	scanner := bufio.NewScanner(os.Stdin)
    	fmt.Printf("Type the year you were born: ")
    	scanner.Scan()
    	// _ should be error, omitted here
    	input, _ := strconv.ParseInt(scanner.Text(), 10, 64)
    	fmt.Printf("You will be %d years old at the end of 2020", 2020-input)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    output:

    Type the year you were born: 1960
    You will be 60 years old at the end of 2020
    
    • 1
    • 2

    6 Arithmetic and math

    Go will not perform implicit type conversion:

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    
    	var num1 float64 = 8
    	var num2 int = 4
    
    	// must convert the type to float64, unlike C
    	answer := num1 / float64(num2)
    
    	// 2.000000
    	fmt.Printf("%f", answer)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7 conditions and boolean expressions

    < > <= >= == !=

    func main() {
    
    	x := 5
    	val := x < 5
    
    	// false
    	fmt.Printf("%t", val)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    8 chained conditionals (AND, OR, NOT)

    9 if, else if, else

    func main() {
    	x := 5
    	y := 5
    	if x == y {
    		fmt.Println("if is true")
    	} else {
    		fmt.Println("if is false")
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    output:

    if is true
    
    • 1

    10 for loops

    func main() {
    	x := 0
    
    	for x < 6 {
    		fmt.Println(x)
    		x++
    	}
    
    	// same as the above loop
    	for x := 0; x < 6; x++ {
    		fmt.Println(x)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    output:

    0
    1
    2
    3
    4
    5
    0
    1
    2
    3
    4
    5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    for {
    
    }
    
    • 1
    • 2
    • 3

    equals to

    for true {
    
    }
    
    • 1
    • 2
    • 3

    both are infinite loops, keywords break and continue can be used to break the loop

    11 switch

    11.1 C-like code:

    func main() {
    	ans := -2
    	switch ans {
    	case 1, -2:
    		fmt.Println("1")
    		fmt.Println("2")
    	case 2:
    		fmt.Println("3")
    	default:
    		fmt.Println(999)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    output:

    1
    2
    
    • 1
    • 2

    11.2 The following syntax also valid:

    func main() {
    	ans := 1
    	switch {
    	case ans > 0:
    		fmt.Println("positive")
    	case ans < 0:
    		fmt.Println("negative")
    	default:
    		fmt.Println("zero")
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    12. Arrays

    The length of an array is fixed,

    func main() {
    	// this array can contain 5 strings at the most
    	var arr [5]string
    
    	// [     ]
    	fmt.Println(arr)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    func main() {
    	// this array can contain 5 strings at the most
    	var arr [5]int
    	// [0 0 0 0 0]
    	fmt.Println(arr)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    concise syntax:

    func main() {
    	arr := [5]int{100}
    	// [100 0 0 0 0]
    	fmt.Println(arr)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    How to get the length of an array:

    arr := [5]int{3, 4, 5, 6, 7}
    
    // 5
    fmt.Println(len(arr))
    
    • 1
    • 2
    • 3
    • 4

    for loop and array:

    func main() {
    	arr := [3]int{4, 5, 6}
    	sum := 0
    
    	for i := 0; i < len(arr); i++ {
    		sum += arr[i]
    	}
    
    	// 15
    	fmt.Println(sum)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    multi-dimensional array:

    arr2D := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    
    // 4
    fmt.Println(arr2D[1][0])
    
    • 1
    • 2
    • 3
    • 4

    13 Slices

    slices are built upon arrays and are more powerful

    func main() {
    	var x [5]int = [5]int{1, 2, 3, 4, 5}
    	// a slice !
    	var s []int  = x[:]
    
    	// [1 2 3 4 5]
    	fmt.Println(s)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    maybe same kind of syntax of slicing with python:

    a[start:stop]  # items start through stop-1
    a[start:]      # items start through the rest of the array
    a[:stop]       # items from the beginning through stop-1
    a[:]           # a copy of the whole array
    a[start:stop:step] # start through not past stop, by step
    a[-1]    # last item in the array
    a[-2:]   # last two items in the array
    a[:-2]   # everything except the last two items
    # Similarly, step may be a negative number:
    a[::-1]    # all items in the array, reversed
    a[1::-1]   # the first two items, reversed
    a[:-3:-1]  # the last two items, reversed
    a[-3::-1]  # everything except the last two items, reversed
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    function append is used to add new elements to a slice:

    func main() {
    	var a []int = []int{5, 6, 7, 8, 9};
    	a = append(a, 10)
    	// [5 6 7 8 9 10]
    	fmt.Println(a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    with function make:

    func main() {
    	// 5 is the capacity of the slice
    	a := make ([]int, 5)
    
    	// [0 0 0 0 0]
    	fmt.Println(a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    14 range

    	var a[]int = []int{1, 2, 3, 6, 7, 8, 9}
    	for index, element := range a {
    
    		// 0 1
    		// 1 2
    		// 2 3
    		// 3 6
    		// 4 7
    		// 5 8
    		// 6 9
    		fmt.Println(index, element)
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    14.1 looking for duplicates, version 1:

    func main() {
    	var a[]int = []int{1, 3, 4, 56, 7, 12, 4, 6}
    	for i, element := range a {
    		for j, element2 := range a {
    			if 	element == element2 && i != j {
    				fmt.Println(i,j,element2)
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    14.2 looking for duplicates, version 2:

    func main() {
    	var a[]int = []int{1, 3, 4, 56, 7, 12, 4, 6}
    	for i, element := range a {
    		for j := i + 1; j < len(a); j++ {
    			element2 := a[j]
    			if element2 == element {
    				fmt.Println(element)
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    15 Maps

    syntax:

    // a map, key is string, value is int
    var mp map[string]int
    
    • 1
    • 2

    example code:

    func main() {
    	var mp map[string]int = map[string]int{
    		"apple":  5,
    		"pear":   6,
    		"orange": 9,
    	}
    	// map[apple:5 orange:9 pear:6]
    	fmt.Println(mp)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    create an empty map:

    mp2 := make(map[string]int)
    
    • 1

    delete, edit, add of map:

    func main() {
    	var mp map[string]int = map[string]int{
    		"apple":  5,
    		"pear":   6,
    		"orange": 9,
    	}
    
    	mp["else"] = 10      // add
    	mp["pear"] = -100    // update
    	delete(mp, "orange") // delete
    
    	// map[apple:5 else:10 pear:-100]
    	fmt.Println(mp)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    checking if a key exists or not:

    var mp map[string]int = map[string]int{
    	"apple":  5,
    	"pear":   6,
    	"orange": 9,
    }
    
    // get to know how many keys in the map
    fmt.Println(len(mp))
    
    // check if a key exists or not
    // exist: ok is true, val = value
    // not exist: ok false, val = default of the type
    val, ok := mp["apple"]
    if (ok) {
    	fmt.Print(val)
    } else {
    	fmt.Println("not exist, default value: ", val)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    output:

    5
    
    • 1

    16 Functions

    func test(x int, y int) {}
    
    // above is the same as
    func test(x, y int) {}
    
    • 1
    • 2
    • 3
    • 4

    syntax:

    // 2 returns
    func test(x, y, z int) (int, int) {
    	return x + y, x - y
    }
    
    // 1 return
    func test(x, y, z int) int {
    	return x + y
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    label return type:

    func test(x, y int) (z1 int, z2 int) {
    // or as below, also valid:
    // func test(x, y int) (z1, z2 int) {
    
    	z1 = x + y
    	z2 = x - y
    
    	// no need to write: return z1, z2
    	return
    }
    
    func main() {
    	ans1, ans2 := test(14, 7)
    
    	// 21, 7
    	fmt.Println(ans1, ans2)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    defer:

    func test(x, y int) (z1 int, z2 int) {
    
    	// delays a function or method
    	// until the function returns
    	// usually used for cleanup
    	// or to close resources
    	defer fmt.Println("hello")
    
    	z1 = x + y
    	z2 = x - y
    	fmt.Println("function will return!")
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    17 Advanced function concepts

    assign function to a variable

    func test() {
    	fmt.Println("Hello")
    }
    
    func main() {
    	x := test
    	x()
    
    	// equals to
    	// test()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    another example:

    func test() {
    	fmt.Println("Hello")
    }
    func main() {
    	test := func() {
    		fmt.Println("hello")
    	}
    	test()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    IIFE: Immediately Invoked Function Expression

    func main() {
    	test := func(x int) int {
    		return x * -1
    	}(99)
    
    	// -99
    	fmt.Println(test)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    function that receive a function as parameter

    func test2(myFunc func(int) int) {
    	fmt.Println(myFunc(7))
    }
    
    func main() {
    	test := func(x int) int {
    		return x * -1
    	}
    
    	test2(test)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Returning a function inside a function:

    func returnFunc(x string) func() {
    
    	// this function called function closure
    	return func() {
    		fmt.Println(x)
    	}
    
    }
    
    func main() {
    	returnFunc("hello")()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    18 mutable & immutable

    slice, map are mutable data types

    func main() {
    	 x := []int{3, 4, 5}
    	 y := x
    	 y[0] = 100
    
    	 // [100 4 5] [100 4 5]
    	 fmt.Println(x, y)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    array is different:

    func main() {
    	x := [2]int{3, 4}
    
    	// y makes a copy of x, get [3, 4]
    	y := x
    
    	// only y changes to [100, 4]
    	// x remains the same
    	y[0] = 100
    
    	// [3 4] [100 4]
    	fmt.Println(x, y)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    19 pointers

    & ampersand: gets the pointer
    * asterik: deference

    func main() {
    	x := 7
    	// 0xc0000a6068
    	fmt.Println(&x)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    func main() {
    	x := 7
    	y := &x
    	// 7 0xc00001a0c8
    	fmt.Println(x, y)
    
    	*y = 8
    
    	// 8 0xc00001a0c8
    	fmt.Println(x, y)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    a string example

    func changeValue(str *string) {
    	*str = "changed!"
    }
    
    func changeValue2(str string) {
    	str = "changed!"
    }
    
    func main() {
    	toChange := "hello"
    	fmt.Println(toChange)
    	changeValue(&toChange)
    	fmt.Println(toChange)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    output:

    hello
    changed!
    
    • 1
    • 2

    and

    hello
    hello
    
    • 1
    • 2

    20 structs

    type Point struct {
    	x        int32
    	y        int32
    	isOnGrid bool
    }
    
    func main() {
    	var p1 Point = Point{1, 2, false}
    	var p2 Point = Point{-5, 7, true}
    	p1.x = 99
    	fmt.Println(p1, p2)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    type Point struct {
    	x        int32
    	y        int32
    }
    
    func main() {
    
    	// only set x, y use default
    	p1 := Point{x: 3}
    	// {3 0}
    	fmt.Println(p1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    use pointer:

    type Point struct {
    	x int32
    	y int32
    }
    
    func changeX(pt *Point) {
    	pt.x = 100
    }
    
    func main() {
    	p1 := &Point{y: 3}
    	// &{0 3}
    	fmt.Println(p1)
    	changeX(p1)
    	// &{100 3}
    	fmt.Println(p1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    without pointer:

    type Point struct {
    	x int32
    	y int32
    }
    
    func changeX(pt Point) {
    	pt.x = 100
    }
    
    func main() {
    	p1 := Point{y: 3}
    	// {0 3}
    	fmt.Println(p1)
    	changeX(p1)
    	// {0 3}
    	fmt.Println(p1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    The following are the same:

    p1 := &Point{y: 3}
    (*p1).x = 8
    
    • 1
    • 2

    and

    p1 := &Point{y: 3}
    p1.x = 8
    
    • 1
    • 2

    struct in struct:

    type Point struct {
    	x int32
    	y int32
    }
    
    type Circle struct {
    	radius float64
    
    	// a name is not required
    	// center *Point
    	*Point
    }
    
    func main() {
    	c1 := Circle{4.56, &Point{4, 5}}
    
    	// 4
    	fmt.Println(c1.x)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    21 structs methods

    A student struct has a method called getAge:

    type Student struct {
    	name   string
    	grades []int
    	age    int
    }
    
    // (s Student) means this is going to
    // act on a Student object
    func (s Student) getAge() int {
    	return s.age
    }
    
    func main() {
    
    	s1 := Student{"Tim", []int{70, 90, 80, 85}, 19}
    
    	// 19, ok
    	fmt.Println(s1.getAge())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    !!The following setAge() method doesn’t work!!

    type Student struct {
    	name   string
    	grades []int
    	age    int
    }
    
    // (s Student) means this is going to
    // act on a Student object
    func (s Student) getAge() int {
    	return s.age
    }
    
    // ! no effect, must use pointer -> (s *Student)
    func (s Student) setAge(age int)  {
    	s.age = age
    }
    
    func main() {
    	s1 := Student{"Tim", []int{70, 90, 80, 85}, 19}
    	// 19
    	fmt.Println(s1.getAge())
    	s1.setAge(39)
    	// 19, didn't change!
    	fmt.Println(s1.getAge())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    correct version:

    type Student struct {
    	name   string
    	grades []int
    	age    int
    }
    
    // (s Student) means this is going to
    // act on a Student object
    func (s Student) getAge() int {
    	return s.age
    }
    
    func (s *Student) setAge(age int)  {
    	s.age = age
    }
    
    func main() {
    	s1 := Student{"Tim", []int{70, 90, 80, 85}, 19}
    	fmt.Println(s1)
    	s1.setAge(39)
    	fmt.Println(s1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    If you have a method that is modifying the object itself, you actually want to make sure that you have the pointer here. For most methods you are always going to want to use the pointer, like:

    func (s *Student) setAge(age int)  { }
    
    • 1

    THE COMMON PRACTICE JUST TAKE THE POINTER ANYWAYS. BECAUSE IT’S NOT REALLY GONNA MATTER IF YOU TAKE THE POINTER VERSUS NOT TAKE IT WHEN YOU ARE RETURNING A VALUE.

    type Student struct {
    	name   string
    	grades []int
    	age    int
    }
    
    
    // here (s *Student) will be also ok
    func (s Student) getAverageGrade() float32 {
    	sum := 0
    	for _, v := range s.grades {
    		sum += v
    	}
    	return float32(sum)/float32(len(s.grades));
    
    }
    
    func main() {
    	s1 := Student{"Tim", []int{70, 90, 80, 85}, 19}
    
    	// 81.25
    	fmt.Println(s1.getAverageGrade())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    22 interfaces

    Interface is a way of looking at a set of related objects or types. For example rectangle and circle are different, but they both have a method called area(), although the implementation are different.
    Interface lets you look at these types as if they are the same. Interface lets us define some kind of behaviour that’s similar between objects or similar between types.

    package main
    
    import (
    	"fmt"
    	"math"
    )
    
    type rect struct {
    	width  float64
    	height float64
    }
    
    type circle struct {
    	radius float64
    }
    
    type shape interface {
    	// Anything, any type, any struct that has
    	// this area() method that returns float64
    	// is of type shape.
    	// It implements the interface shape.
    	area() float64
    
    	// if needed, more methods can be added
    	// pow(x int) float64
    }
    
    // rect implements the interface shape
    // rect is a type of shape
    func (r rect) area() float64 {
    	return r.width * r.height
    }
    
    // circle has implemented the interface shape too
    // circle is a type of shape too
    func (c circle) area() float64 {
    	return math.Pi * c.radius * c.radius
    }
    
    func main() {
    	c1 := circle{4.5}
    	r1 := rect{5, 7}
    
    	// then the below code should work!
    	shapes := []shape{c1, r1}
    
    	for _, shape := range shapes {
    		fmt.Println(shape.area())
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    output:

    63.61725123519331
    35
    
    • 1
    • 2

    Interfaces can be used as parameter type, return type, variable type, etc, very flexible

    func getArea(s shape) float64 {
    	return s.area()
    }
    func main() {
    	shapes := []shape{c1, r1}
    	for _, shape := range shapes {
    		fmt.Println(getArea(shape))
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    If pointer is used:

    package main
    
    import (
    	"fmt"
    	"math"
    )
    
    type rect struct {
    	width  float64
    	height float64
    }
    
    type circle struct {
    	radius float64
    }
    
    type shape interface {
    	// Anything, any type, any struct that has
    	// this area() method that returns float64
    	// is of type shape.
    	// It implements the interface shape.
    	area() float64
    
    	// if needed, more methods can be added
    	// pow(x int) float64
    }
    
    func getArea(s shape) float64 {
    	return s.area()
    }
    
    // rect implements the interface shape
    // rect is a type of shape
    func (r *rect) area() float64 {
    	return r.width * r.height
    }
    
    // circle has implemented the interface shape too
    // circle is a type of shape too
    func (c *circle) area() float64 {
    	return math.Pi * c.radius * c.radius
    }
    
    func main() {
    	c1 := circle{4.5}
    	r1 := rect{5, 7}
    
    	shapes := []shape{&c1, &r1}
    
    	for _, shape := range shapes {
    		fmt.Println(getArea(shape))
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    An object can implement multiple interfaces, not just one.


    youtube 视频:
    https://www.youtube.com/watch?v=lh_Uv2imp14 1 ~ 22

  • 相关阅读:
    点餐小程序实战教程01需求分析
    HarmonyOS 开发之———应用程序入口—UIAbility的使用
    Codechef [June Long Two 2022] 题解
    FreeSql 将 Saas 租户方案精简到极致[.NET ORM SAAS]
    字节最新算法题解:在排序数组中查找元素的第一个和最后一个位置
    Autoware.universe部署06:使用DBC文件进行UDP的CAN通信代码编写
    C/C++字符判断 2021年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析
    C++实现Wlan自动连接(wpa2 enterprise)
    9.4黄金行情是否反转?今日多空如何布局?
    使用mybatis_plus快速实现分页插件
  • 原文地址:https://blog.csdn.net/ftell/article/details/127748426