Эти ямы в языке Go

Java задняя часть Go PhpStorm

Golang — мой любимый язык, он краток, эффективен, прост в изучении, очень эффективен в разработке и может быть скомпилирован в машинный код... Несмотря на то, что он привлек к себе много внимания, как только родился, и постепенно становится популярным на рынке, в конце концов, это новый язык, и есть еще много мест, к которым люди не привыкли (например, ямы, (^__^)) Как новичок, я учусь, наступая на яму, надеясь быть примером для других.

Не начинайте имя файла просто с__test.goв конец

Имена исходных файлов Golang ничем не отличаются от других языков, но Golang поставляется сUnit test,этоunit testЕсть небольшая спецификация: всеunit testфайлы должны быть__test.goна конец! Поэтому, когда вы называете не-unit testФайл XXX_test.go, и когда вы настаиваете на компиляции, будет сообщено об ошибке:no buildable Go source files in XXXXXX(你的文件路径). Итак, не забудьте__test.goна конецunit testфайл и не забудьте не включатьunit testФайл ставится вместе с обычными файлами Go, обязательно ставьтеunit testФайлы вместе помещаются в каталог, иначе они не будут компилироваться.

утверждениеfmt.Println("这里是汉字:" + 字符串变量)Проблема в том, что значение строковой переменной нельзя распечатать

Существуют следующие процедуры:

package main

import "fmt"

func main()  {
    m1 := getString()

    fmt.Println("现在是:" + m1)
}

func getString()string{
    return "abd"
}

Команда Rungo run test.go

но печатать переменные по отдельностиm1но он может отображаться нормально

import "fmt"

func main()  {
    m1 := getString()

    fmt.Println(m1)

    fmt.Println("现在是:" + m1)
}

func getString()string{
    return "abd"
}

Почему это? Очень странно! На самом деле виновата именно IDE.Моя IDE - это пакет плагинов phpstorm + Golang.Консоль, которая идет в комплекте с IDE, очень недружелюбна к китайской поддержке.После печати китайских строчек легко отобразить не полностью .terminalРаспечатайте, это правильно!

несколькоdeferПри появлении несколькоdeferВыполнять в порядке LIFO (последний пришел — первый вышел)

package main

import "fmt"

func main(){
    defer func(){
        fmt.Println("1")
    }()

    defer func(){
        fmt.Println("2")
    }()

    defer func(){
        fmt.Println("3")
    }()


}

Соответствующий вывод:

3
2
1

panicМожно передать любое значение, не только строку

package main

import "fmt"

func main(){

    defer func(){
        if r := recover();r != nil{
            fmt.Println(r)
        }
    }()

    panic([]int{12312})
}

вывод:

[12312]

использоватьfor rangeПри обходе массива или карты пройденный указатель не изменяется, и каждый обход выполняет только копию значения структуры.

import "fmt"

type student struct{
    Name string
    Age  int
}

func main(){
    var stus []student

    stus = []student{
        {Name:"one", Age: 18},
        {Name:"two", Age: 19},
    }

    data := make(map[int]*student)

    for i, v := range stus{
        data[i] = &v   //应该改为:data[i] = &stus[i]
    }

    for i, v := range data{
        fmt.Printf("key=%d, value=%v \n", i,v)
    }
}

Итак, результирующий вывод:

key=0, value=&{two 19} 
key=1, value=&{two 19}

В Go нет наследования! Нет наследства! В Го это называется комбинацией! Это комбинация!

import "fmt"

type student struct{
    Name string
    Age  int
}

func (p *student) love(){
    fmt.Println("love")

}

func (p *student) like(){
    fmt.Println("like first")
    p.love()
}

type boy struct {
    student
}

func (b * boy) love(){
    fmt.Println("hate")
}

func main(){

    b := boy{}

    b.like()
}

вывод:

like first
love

Независимо от порядка выполнения, когда параметр является функцией, сначала необходимо вычислить значение параметра.

func main(){
    a := 1
    defer print(function(a))
    a = 2;
}

func function(num int) int{
    return num
}
func print(num int){
    fmt.Println(num)
}

вывод:

1

Обратите внимание, чтоstructфункция или* structФункция

import "fmt"

type people interface {
    speak()
}

type student struct{
    name string
    age int
}
func (stu *student) speak(){
    fmt.Println("I am a student, I am ", stu.age)
}


func main(){
    var p people
    p = student{name:"RyuGou", age:12} //应该改为 p = &student{name:"RyuGou", age:12}
    p.speak()
}

вывод:

cannot use student literal (type student) as type people in assignment:
student does not implement people (speak method has pointer receiver)

make(chan int)иmake(chan int, 1)разные

chanПосле записи данных текущийgoruntineОн будет блокироваться до тех пор, пока его кто-нибудь не получит (например, "

import "fmt"


func main(){
    ch := make(chan int) //改为 ch := make(chan int, 1) 就好了

    ch <- 1

    fmt.Println("success")
}

вывод:

fatal error: all goroutines are asleep - deadlock!

Функция выбора golang аналогична функциям select, poll и epoll, которая заключается в отслеживании операций ввода-вывода и запуске соответствующих действий при выполнении операций ввода-вывода.

Кодовая форма команды select очень похожа на команду switch, но оператором операции в случае select может быть только «операция ввода-вывода» (а не только значение<-channel, назначатьchannel<-Также может быть), select будет ждать, пока не завершится оператор case, то есть пока данные не будут успешно прочитаны из канала. тогда оператор select заканчивается

 import "fmt"


func main(){
    ch := make(chan int, 1)

    ch <- 1

    select {
    case msg :=<-ch:
        fmt.Println(msg)
    default:
        fmt.Println("default")
    }

    fmt.Println("success")
}

вывод:

1
success

defaultМожет определить, заполнен ли чан

import "fmt"


func main(){
    ch := make(chan int, 1)

    select {
    case msg :=<-ch:
        fmt.Println(msg)
    default:
        fmt.Println("default")
    }

    fmt.Println("success")
}

вывод:

default
success

В это время, потому чтоchВ него не записываются никакие данные, он пустой, поэтому кейс не будет успешно прочитан. Затем select выполняет оператор по умолчанию.

Неинициализированные переменные не существуют в Go

Основной способ определения переменных:

var 发量名字 类型 = 表达式

Если и тип, и выражение могут быть опущены, если выражение инициализатора опущено, переменная будет инициализирована с нулевым значением.

  • Числовые переменные соответствуют значению 0
  • логическая переменная соответствует false
  • Нулевое значение, соответствующее строке, является пустой строкой
  • Переменные интерфейса или ссылочного типа (включая slice, map, chan) соответствуют nil
  • Нулевое значение, соответствующее агрегатному типу, такому как массив или структура, является нулевым значением, соответствующим каждому элементу или полю этого типа.
 var s string 
 fmt.Println(s) // ""

:=Вопросы внимания

  • использовать:=Определенные переменные могут использоваться только внутри функций.
  • При определении нескольких переменных:=Не все окружение просто объявлено, некоторые могут быть просто назначены, например, переменная err ниже
    in, err := os.Open(infile)
    // TODO
    out, err := os.Create(outfile)
    

newЭто просто предопределенная функция в языке Go, это не ключевое слово, мы можем поставитьnewкак переменная или другое

Например:

func delta(old, new int) int { 
    return new - old 
}

Вышесказанное верно.

не используетсяnewвыделит память в куче

Компилятор автоматически выбирает, выделять память в стеке или в куче, но, как это ни удивительно, этот выбор не диктуетсяvarвсе ещеnewЭто зависит от того, как вы объявляете переменную.

См. пример:


var global *int 

func f() {
    var x int x=1 
    global = &x
}

func g() {
    y := new(int)
    *y = 1 
}

f()в функцииxзаключается в выделении памяти в куче, иg()в функцииyразмещается в стеке.

initФункции могут содержать несколько функций в одном файле.

В одном файле пакета может быть несколькоinitфункция, несколькоinitПорядок выполнения функций согласуется с порядком определения.

В Голанге нет «объекта».

package main

import (
    "fmt"
)
type test struct {
    name string
}
func (t *test) getName(){
    fmt.Println("hello world")
}
func main() {
    var t *test
    t = nil
    t.getName()
}

Может нормально выводить? Сообщит об ошибке?

Результат:

hello world

может выводить нормально. Go не является объектно-ориентированным языком по своей природе. В Go нет значения объекта. Объекты в книгах по языку Go также отличаются от объектов в Java и PHP. Это не настоящие «объекты», а сущности структуры в Go. .

Вызовите метод getName, который также можно преобразовать в Go, преобразовав в: Type.method(t Type, arguments) Следовательно, основная функция приведенного выше кода также может быть записана как:

func main() {
    (*test).getName(nil)
}

Указатели в Go*значение символов

Все знают значение &, возьмите адрес, если хотите получить адрес переменной, просто добавьте & перед переменной.

Например:

a := 1
b := &a

Теперь я получаю адрес a, но хочу получить значение, на которое указывает указатель a, как это сделать? использовать*номер,*bВот и все. * означает получение значения из указателя.

Добавьте единицу к значению a

a := 1
b := &a
*b++

*и&могут компенсировать друг друга, отмечая при этом, что*&можно компенсировать, но&*нельзя, поэтомуaи*&aтакой же как*&*&*&aТо же самое справедливо.

os.ArgsПолучить параметры команды командной строки, должны начинаться с 1 координаты массива

os.Argsпервый элемент ,os.Args[0], это имя самой команды

package main
import (
    "fmt"
    "os"
)
func main() {
    fmt.Println(os.Args[0])
}

Приведенный выше код послеgo buildПосле этого упакуйте его в исполняемый файлmain, затем выполните команду./main 123

вывод:./main

Ошибка, вызванная проблемой емкости массива slice slice

См. следующий код:

import (
    "fmt"
)
func main(){
    array := [4]int{10, 20, 30, 40}
    slice := array[0:2]
    newSlice := append(slice, 50)
    newSlice[1] += 1
    fmt.Println(slice)
}

Подскажите, пожалуйста, что на выходе? ответ:

[10 21]

Если сделать небольшую модификацию, указанный выше новый фрагмент будет расширен три раза, новый фрагмент := append(append(append(slice, 50), 100), 150) следующим образом:

import (
    "fmt"
)
func main(){
    array := [4]int{10, 20, 30, 40}
    slice := array[0:2]
    newSlice := append(append(append(slice, 50), 100), 150)
    newSlice[1] += 1
    fmt.Println(slice)
}

Результат:

[10 20]

Что это, черт подери, такое? Это начинается с расширения слайсов Golang; расширение слайсов означает, что когда слайс добавляет элементы, емкости слайса будет недостаточно, и емкость слайса будет расширена. Размер расширения следует следующим принципам: (Если емкость среза меньше 1024 элементов, тогда при расширении емкости шапка слайса удваивается и умножается на 2, как только количество элементов превышает 1024 элемента, коэффициент роста становится равным 1,25, то есть четверть исходной емкости увеличивается каждый раз.) Если емкость не затрагивается после расширения Емкость исходного массива, то место, на которое указывает указатель в срезе, все еще является исходным массивом (это причина для ошибка); если емкость исходного массива будет превышена после расширения, то Go откроет новый кусок памяти, Скопируйте исходное значение поверх, эта ситуация никак не повлияет на исходный массив. Рекомендуется максимально избегать ошибок.

mapСсылается на несуществующий ключ, не сообщая об ошибке

Каков результат следующего примера, будет ли он сообщать об ошибке?

import (
    "fmt"
)

func main(){
    newMap := make(map[string]int)
    fmt.Println(newMap["a"])
}

ответ:

0

Не сообщайте об ошибке. В отличие от PHP, карта Golang похожа на HashMap в Java, Java вернет null, если ссылка не существует, а Golang вернет начальное значение.

карта использует диапазон для обхода проблемы порядка, а не порядок входа, а случайный порядок

См. пример ниже:


import (
    "fmt"
)

func main(){
    newMap := make(map[int]int)
    for i := 0; i < 10; i++{
        newMap[i] = i
    }
    for key, value := range newMap{
        fmt.Printf("key is %d, value is %d\n", key, value)
    }
}

вывод:

key is 1, value is 1
key is 3, value is 3
key is 5, value is 5
key is 7, value is 7
key is 9, value is 9
key is 0, value is 0
key is 2, value is 2
key is 4, value is 4
key is 6, value is 6
key is 8, value is 8

Это хаотическая последовательность. Порядок обхода карты не является фиксированным.Такая конструкция предназначена для предотвращения того, чтобы программы полагались на определенный порядок обхода.

Канал передается как параметр функции и может быть объявлен как только для выборки (

Когда функция объявляет канал как параметр типа, она может объявить channl как только принимающий значения (

Например: можно отправлять только значения

func setData(ch chan <- string){
    //TODO
}

Если в приведенной выше функции есть

Ниже приведены только значения, которые могут быть приняты:

func setData(ch <- chan  string){
    //TODO
}

Если в приведенной выше функции есть ch

При использовании каналов обратите внимание на поток выполнения между горутинами.

package main
import (
    "fmt"
)
func main(){
    ch := make(chan string)
    go setData(ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}
func setData(ch  chan  string){
    ch <- "test"
    ch <- "hello wolrd"
    ch <- "123"
    ch <- "456"
    ch <- "789"
}

Каков поток выполнения приведенного выше кода? Операция отправки или значения, основанная на небуферизованном канале, приведет к блокировке текущей горутины, и она не будет нормально работать до тех пор, пока другая горутина не выполнит противоположное значение или операцию отправки. Поток в приведенном выше примере выглядит следующим образом:

Основная горутина ожидает приема, а другая горутина отправляет «тест» и ожидает обработки; после завершения связи печатается «тест»; две горутины продолжают выполнять свои собственные. Основная горутина ожидает приема, а другая горутина отправляет «hello world» и ждет обработки; после завершения связи она печатает «hello world»; две горутины продолжают выполнять свои собственные. Основная горутина ожидает получения, а другая горутина отправляет «123» и ожидает обработки; после завершения связи выводится «123»; две горутины продолжают выполнять свои собственные. Основная горутина ожидает получения, а другая горутина отправляет «456» и ожидает обработки; после завершения связи выводится «456»; две горутины продолжают выполнять свои собственные. Основная горутина ожидает приема, а другая горутина отправляет «789» и ожидает обработки; после завершения связи выводится «789»; две горутины продолжают выполнять свои собственные.

Помните: канал Golang используется для связи между горутинами, и процесс связи будет заблокирован.

Эти ямы в языке Go

Яма 3 языка Go

Для получения более интересного контента, пожалуйста, обратите внимание на мой публичный аккаунт WeChat.互联网技术窝Или добавьте WeChat для обсуждения и общения: