Задайте вопрос Go, в чем разница между строкой len == 0 и строкой == "" ?

Go

Если у вас есть какие-либо вопросы или предложения, добро пожаловать на общение и столкновение во времени. Мой официальный аккаунт [Brain fried fish], адрес GitHub:GitHub.com/Vicious Genetics.

Всем привет, я жареная рыба.

Несколько дней назад я увидел, как несколько воротил обсуждают проблему в группе WeChat: "В чем разница между строкой len == 0 и строкой == ""? "

Это относительно небольшая деталь, и она также вызывает у меня любопытство, поэтому сегодня я буду изучать с вами в этой статье, есть ли разница между ними, и чья производительность лучше?

метод тестирования

В тестовом методе мы отдельно объявляемTest1а такжеTest2метод:

func Test1() bool {
	var v string
	if v == "" {
		return true
	}
	return false
}

func Test2() bool {
	var v string
	if len(v) == 0 {
		return true
	}
	return false
}

Внутри метода делается только простое объявление типа переменной, основанное на string == "" и string len == 0 соответственно.

прецедент

Напишите бенчмарк из двух методов для последующего тестирования производительности:

func BenchmarkTest1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Test1()
	}
}

func BenchmarkTest2(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Test2()
	}
}

Анализ результатов

$ go test --bench=. -benchmem
goos: darwin
goarch: amd64
BenchmarkTest1-4   	1000000000	         0.305 ns/op	       0 B/op	       0 allocs/op
BenchmarkTest2-4   	1000000000	         0.305 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	_/Users/eddycjy/go-application/awesomeProject/tests	0.688s

По результатам нескольких тестов сравниваются два:

  • Разницы в производительности почти нет, и может даже возникнуть точно такая же ситуация.
  • Ни приложение памяти, ни операция не задействованы, оба являются 0/op. Это означает, что переменная не объявлена, есть действие инициализации, и этот компилятор Go сделал оптимизацию.

Результат на самом деле тот же. Согласно подсказке Цао Да, мы можем более внимательно изучить ассемблерный код этих двух, чтобы увидеть, в чем конкретно разница:

$ go tool compile -S main.go
"".main STEXT nosplit size=1 args=0x0 locals=0x0
	0x0000 00000 (main.go:3)	TEXT	"".main(SB), NOSPLIT|ABIInternal, $0-0
	0x0000 00000 (main.go:3)	FUNCDATA	$0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (main.go:3)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (main.go:5)	RET
	0x0000 c3                                               .
go.cuinfo.packagename. SDWARFINFO dupok size=0
	0x0000 6d 61 69 6e                                      main
""..inittask SNOPTRDATA size=24
	0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
	0x0010 00 00 00 00 00 00 00 00                          ........
gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
	0x0000 01 00 00 00 00 00 00 00   

Будь тоlen(v) == 0, илиv == ""Оценка скомпилированного ассемблерного кода полностью согласуется. Понятно, что компилятор Go сделал явные оптимизации в этой области, и велика вероятность прямого сравнения.

Есть ли у вас какие-либо другие взгляды и расширения? Добро пожаловать, чтобы учиться и обмениваться вместе.

мой публичный аккаунт

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

Лучшие отношения - это достигать друг друга, твойподобното естьжареная рыбаСамая большая мотивация для творчества, спасибо за поддержку.