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 используется для связи между горутинами, и процесс связи будет заблокирован.