набор ошибок голанга

задняя часть Go PHP JSON

Эта статьяЭти ямы в языке Goтри.

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

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

import (
	"fmt"
	"runtime"
	"time"
)

func main(){
	names := []string{"lily", "yoyo", "cersei", "rose", "annei"}
	for _, name := range names{
		go func(){
			fmt.Println(name)
		}()
	}
	runtime.GOMAXPROCS(1)
	runtime.Gosched()
}

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

Отвечать:

annei
annei
annei
annei
annei

Зачем? Вы немного удивлены? Вывод «annei», а «annei» — последний элемент «names», что означает, что программа печатает значение последнего элемента, а name — внешнее значение для анонимных функций. Отсюда можно сделать вывод: хотя в каждом цикле включена сопрограмма, но эти сопрограммы ссылаются на внешние переменные, при создании сопрограммы и выполнении действия печати значение имени неизвестно, что изменилось, т.к. тоже работает сопрограмма функции, все работают параллельно, но здесь из-за того, что длина массива имен слишком мала, при создании сопрограммы основной цикл функции уже закончился, поэтому печатаются все пройденные имена. элемент «анней». Как подтвердить вышеизложенный вывод? На самом деле это очень просто: после каждого цикла делайте небольшую паузу и ждите, пока сопрограмма напечатает текущее имя.

import (
	"fmt"
	"runtime"
	"time"
)

func main(){
	names := []string{"lily", "yoyo", "cersei", "rose", "annei"}
	for _, name := range names{
		go func(){
			fmt.Println(name)
		}()
		time.Sleep(time.Second)
	}
	runtime.GOMAXPROCS(1)
	runtime.Gosched()
}

распечатать результат:

lily
yoyo
cersei
rose
annei

Выше мы приходим к выводу, не делайте никаких предположений о времени выполнения «функции go», если вы действительно не можете дать гарантии, которые делают это предположение абсолютным фактом.

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

Пожалуйста, посмотрите на код, он нормально компилируется?

import (
	"fmt"
)
type Lili struct{
	Name string
}

func (Lili *Lili) fmtPointer(){
	fmt.Println("poniter")
}

func (Lili Lili) fmtReference(){
	fmt.Println("reference")
}


func main(){
	li := Lili{}
	li.fmtPointer()
}

Отвечать:

能正常编译通过,并输出"poniter"

Чувствуя себя немного удивленным, посмотрите на следующий код, как его можно скомпилировать и передать?

import (
	"fmt"
)
type Lili struct{
	Name string
}

func (Lili *Lili) fmtPointer(){
	fmt.Println("poniter")
}

func (Lili Lili) fmtReference(){
	fmt.Println("reference")
}


func main(){
	Lili{}.fmtPointer()
}

Отвечать:

不能编译通过。
“cannot call pointer method on Lili literal”
“cannot take the address of Lili literal”

Это немного странно? Почему это? На самом деле в первом примере кода «li» в функции main является переменной.Хотя li имеет тип Lili, li является адресным, а тип &li —*Lili, поэтому методы *Lili можно назвать.

Интерфейс, содержащий нулевой указатель, не является нулевым интерфейсом.

Взгляните на следующий код, что он возвращает?

import (
	"bytes"
	"fmt"
	"io"
)

const debug = true

func main(){
	var buf *bytes.Buffer
	if debug{
		buf = new(bytes.Buffer)
	}
	f(buf)
}
func f(out io.Writer){

	if out != nil{
		fmt.Println("surprise!")
	}
}

Ответ на выходе: удивление. хорошо, давайтеdebugвыключить, иdebugзначение становитсяfalse. Итак, каков результат? Ничего не выводит?

import (
	"bytes"
	"fmt"
	"io"
)

const debug = false

func main(){
	var buf *bytes.Buffer
	if debug{
		buf = new(bytes.Buffer)
	}
	f(buf)
}
func f(out io.Writer){

	if out != nil{
		fmt.Println("surprise!")
	}
}

Ответ таков: все-таки выходное удивление.

Почему это? Это включает в себя концепцию, которая касается значений интерфейса. Концептуально значение интерфейса делится на две части: одна — тип, а другая — значение, соответствующее типу, которые называются: динамический тип и динамическое значение. Системы типов предназначены для скомпилированных языков, тип — это концепция времени компиляции, поэтому тип не является значением. В приведенном выше коде параметру out функции f присваивается значение*bytes.Bufferявляется нулевым указателем, поэтому динамическое значение out равно нулю. Однако его динамический тип — *bytes.Buffer, что означает: «Интерфейс, отличный от nil, содержащий нулевой указатель», поэтому результат «out!=nil» по-прежнему верен. Однако для прямого*bytes.BufferОбнуление типов не имеет этой проблемы.

import (
	"bytes"
	"fmt"
)

func main(){
	var buf *bytes.Buffer
	if buf == nil{
		fmt.Println("right")
	}
}

Или вывод: правильно Вышеупомянутая яма появится только тогда, когда указатель интерфейса будет передан в параметр интерфейса функции. Это также очень легко изменить,*bytes.Bufferизменить наio.WriterДостаточно.

import (
	"bytes"
	"fmt"
	"io"
)
const debug = false
func main(){
	var buf  io.Writer //原来是var buf *bytes.Buffer
	if debug{
		buf = new(bytes.Buffer)
	}
	f(buf)
}
func f(out io.Writer){
	if out != nil{
		fmt.Println("surprise!")
	}
}

При преобразовании карты в строку json порядок в строке json не имеет ничего общего с порядком назначения карты

Пожалуйста, посмотрите на следующий код, каков результат? Если это строка json, каков порядок ключей в строке json?

func main() {
	params := make(map[string]string)

	params["id"] = "1"
	params["id1"] = "3"
	params["controller"] = "sections"

	data, _ := json.Marshal(params)
	fmt.Println(string(data))
}

Ответ: вывод{"controller":"sections","id":"1","id1":"3"}Использование пакета преобразования json, который поставляется с Golang, изменит порядок ключей на карте на алфавитный порядок вместо порядка назначения карты. Даже если используется структура картыfor rangeПри обходе ключи в нем тоже неупорядоченные.Можно понять, что карта представляет собой неупорядоченную структуру, которую следует отличать от массива в php.

Json десериализует числа в значения типа interface{}, по умолчанию анализируемые как float64

См. следующую программу, программа хочет вывести целое число в данных json.idплюс3значение, программа сообщит об ошибке?


func main(){
	jsonStr := `{"id":1058,"name":"RyuGou"}`
	var jsonData map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &jsonData)

	sum :=  jsonData["id"].(int) + 3
	fmt.Println(sum)
}

Ответ заключается в том, что будет сообщено об ошибке, и вывод будет таким:

panic: interface conversion: interface {} is float64, not int

При использовании Golang для анализа данных формата JSON, если данные получены в интерфейсе{}, они будут проанализированы в соответствии со следующими правилами:

bool, for JSON booleans

float64, for JSON numbers

string, for JSON strings

[]interface{}, for JSON arrays

map[string]interface{}, for JSON objects

nil for JSON null

Следует изменить на:

func main(){
	jsonStr := `{"id":1058,"name":"RyuGou"}`
	var jsonData map[string]interface{}
	json.Unmarshal([]byte(jsonStr), &jsonData)

	sum :=  int(jsonData["id"].(float64)) + 3
	fmt.Println(sum)
}

Даже если имеется несколько переменных, некоторые переменные существуют, а некоторые переменные не существуют, и эти переменные назначаются вместе, их нельзя использовать.:=чтобы присвоить значение глобальной переменной

:=Он часто используется для объявления локальных переменных.Когда присваивается несколько переменных и существуют некоторые значения,:=Его также можно использовать для присваивания, например:

msgStr := "hello wolrd"
msgStr, err := "hello", errors.New("xxx")//err并不存在

Однако, если глобальные переменные также назначены подобным образом, будут проблемы.Пожалуйста, посмотрите на следующий код.Вы можете его скомпилировать?

var varTest string

func test(){
	varTest, err := function()
	fmt.Println(err.Error())
}

func function()(string, error){
	return "hello world", errors.New("error")
}


func main(){
	test()
}

Ответ: никак. вывод:

varTest declared and not used

Но если вы измените его на следующий код, вы можете пройти:

var varTest string

func test(){
	err := errors.New("error")
	varTest, err = function()
	fmt.Println(err.Error())
}

func function()(string, error){
	return "hello world", errors.New("error")
}


func main(){
	test()
}

вывод:

error

Что является причиной этого? Ответ на самом деле довольно прост, вtestметод, если вы используетеvarTest, err := function()Таким образом, это эквивалентно определению других и глобальных переменных в функции.varTestЛокальная переменная с таким же именем, и эта локальная переменная не используется, поэтому компилироваться не будет.

* интерфейс - это тип указателя на интерфейс, а не тип интерфейса

Можно ли скомпилировать следующий код?

import (
	"fmt"
)

type Father interface {
	Hello()
}


type Child struct {
	Name string
}

func (s Child)Hello()  {

}

func main(){
	var buf  Child
	buf = Child{}
	f(&buf)
}
func f(out *Father){
	if out != nil{
		fmt.Println("surprise!")
	}
}

Ответ: он не может быть скомпилирован. вывод:

*Father is pointer to interface, not interface

Примечание. Переменная типа интерфейса может быть присвоена экземпляру структуры, реализующей интерфейс, но это не означает, что указатель на интерфейс может быть присвоен экземпляру указателя структуры, реализующей интерфейс. который:

var buf Father = Child{}

Да, но

var buf *Father = new(Child)

Но это неправильно. Следует изменить на:

 var buf Father = Child{}
 var pointer *Father = &buf

Чтобы скомпилировать код в начале проблемы, изменив приведенный выше код на:

import (
	"fmt"
)

type Father interface {
	Hello()
}


type Child struct {
	Name string
}

func (s Child)Hello()  {

}

func main(){
	var buf  Father
	buf = Child{}
	f(&buf)
}
func f(out *Father){
	if out != nil{
		fmt.Println("surprise!")
	}
}