Go语言入门

Go语言入门,第1张

概述Go语言入门安装Go环境安装集成开发环境语法基础包包的声明包的导入导出名函数函数定义参数列表简化多返回值返回值的命名变量变量的初始化短赋值语句基本数据类型整型浮点型布尔型其他数字类型零值分支结构forifswitchdefer指针结构体数组切片映射go程信道SelectMut

Go语言入门安装Go环境安装集成开发环境语法基础包包的声明包的导入导出名函数函数定义参数列表简化多返回值返回值的命名变量变量的初始化短赋值语句基本数据类型整型浮点型布尔型其他数字类型零值分支结构forifswitchdefer指针结构体数组切片映射go 程信道SelectMutex

安装Go环境

安装包下载地址:https://golang.org/dl/,打不开可以在https://studygolang.com/dl下载。


下载安装完成后可打开Win+R进入cmd查看是否安装成功,输入go version 成功显示版本号则安装成功

安装集成开发环境

liteIDE下载地址:http://liteIDe.org/cn/
可以使用Go的集成开发环境liteIDE,或是IntelliJ IDea安装Go插件。
插件安装路径:file->Settings

语法基础包包的声明

每个go文件的第一行声明该文件属于哪个包,package 包名 定义该文件的包名,main包表示独立可运行的go程序,每个go应用程序都包含一个叫main的包。

package main
包的导入

使用import关键字 + 包名导入依赖的包,包名使用双引号。

import "fmt"import "math"

也可以使用圆括号分组形式导入包

import (	"fmt" 	"math")
导出名

在go中,只能使用模块中已导出的函数,已导出的函数都以大写字母开头。小写字母开头的方法只能在包内使用。

package mainimport ("fmt"	"math")func main() {	fmt.Printf("%g", math.Sqrt(2))}

package mainimport ("fmt"	"math")func main() {	fmt.Printf("%g", math.sqrt(2))}

函数函数定义

go中的函数使用func关键字定义,注意参数类型在参数名之后,格式如下

func 函数名(参数名1 参数类型, 参数名2 参数类型) 返回值 {}
package mainimport (	"fmt")func main() {	fmt.Printf("3 + 5 = %d", add(3, 5))}func add(a int, b int) int {	return a + b}
参数列表简化

当两个或以上参数类型相同时,参数类型可只保留最后一个,如上函数add可简化为

func add(a, b int) int {	return a + b}
多返回值

go中的函数可返回任意数量的返回值

package mainimport (	"fmt")func main() {	a, b := add(3, 5)	fmt.Printf("3 + 5 = %d, 3 - 5 = %d", a, b)}func add(a, b int) (int, int) {	return a + b, a - b}
返回值的命名

可以直接命名返回值,没有参数的return语句返回已命名的返回值

func add(a, b int) (sum, difference int) {	sum = a + b	difference = a - b	return}
变量

变量使用var关键字定义,作用域可以是包或函数。

var flag boolfunc main() {	var i int	flag = true	i = 5	fmt.Println(i, flag)}
变量的初始化

变量可以在声明时初始化,如果变量在声明时初始化值可省略类型,变量可以从值中获取类型。

var flag = truefunc main() {	var i = 5	fmt.Println(i, flag)}
短赋值语句

在函数里:=可以取代类型明确的变量赋值中的var声明,但在函数外不可以使用

func main() {	i := 5	fmt.Println(i, flag)}
基本数据类型

go中的基本数据类型同样可分为整型、浮点型、布尔型三大类

整型

整型的数据类型包含int8、int16、int32、int64、uint8、uint16、uint32、uint64,其中int开头的为有符号整型,unit开头的位无符号整型

浮点型

浮点型的数据类型包含float32、float64、complex64、complex128、uint8、uint16、uint32、uint64,其中int开头的为有符号整型,unit开头的位无符号整型。
float用于表示浮点数据,complex用于表是复数类型

布尔型

布尔型的值只可以是常量 true 或者 false

其他数字类型

其他数字类型包括byte、rune。
byte 等同于int8,常用来处理ascii字符
rune 等同于int32,常用来处理unicode或utf-8字符

// rune is an alias for int32 and is equivalent to int32 in all ways. It is// used, by convention, to distinguish character values from integer values.//int32的别名,几乎在所有方面等同于int32//它用来区分字符值和整数值type rune = int32
零值

没有赋值的变量会被设置为零值
数字型:0
布尔型:false
字符串:""

package mainimport (	"fmt")var (	flag bool	MaxInt uint64	str string)func main() {	fmt.Printf("Type: %T Value: %v\n", flag, flag)	fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)	fmt.Printf("Type: %T Value: %v\n", str, str)}

分支结构

go语言中的循环结构只有for一种

for

对比其他语言,go中的for的小括号可以省略

	sum := 0	for i:= 1; i < 100; i ++ {		sum += i	}	fmt.Printf("sum = %v", sum)

除了条件表达式外,初始化语句和后置语句是可选的

	sum := 1	for sum < 10 {		sum += sum	}	fmt.Printf("sum = %v", sum)

无限循环语句可视作没有条件表达式的for语句

	for {	}
if

if语句和for语句类似,小括号可以省略,大括号不行

	flag := true	if flag {		fmt.Printf("true")	} else {		fmt.Printf("false")	}

if 可以在条件表达式判定之前先做一些初始化的语句,该语句的作用域仅在if语句内有效

import (	"fmt"	"math")func pow(x, n, lim float64) float64 {	if v := math.Pow(x, n); v < lim {		return v	}	return lim}func main() {	fmt.Println(		pow(3, 2, 10),		pow(3, 3, 20),	)}

switch

go中的switch 的 case 语句从上到下顺次执行,直到匹配成功时停止,不会发生case穿透,只会执行第一个满足条件的case而不会执行后面的case

import (	"fmt"	"runtime")func main() {	fmt.Print("Go runs on ")	switch os := runtime.GOOS; os {	case "darwin":		fmt.Println("OS X.")	case "linux":		fmt.Println("linux.")	case "windows":		fmt.Println("windows")	default:		fmt.Printf("NulL")	}}

defer

defer修饰的语句会被推到调用栈里,待外层函数返回后执行,如果有多条语句用defer修饰,遵循后进先出的顺序

	fmt.Println("counting")	for i := 0; i < 10; i++ {		defer fmt.Println(i)	}	fmt.Println("done")

指针

go中有指针,但不允许进行指针计算,* 类型声明这种类型的指针,零值为<nil>。
使用& *** 作符生成指向指定 *** 作数的指针。

func main() {	i := 1	var p *int	fmt.Println(p)	p = &i//定义指向变量i的指针p	fmt.Println(p)//变量i在内存中的存放地址	fmt.Println(*p)	*p = *p + 1	fmt.Println(*p)}

结构体

结构体(struct)就是一组字段,使用.号访问结构体中的字段

type Coordinate struct {	X int	Y int}func main() {	v := Coordinate{1, 2}	fmt.Println(v.X)}

可使用结构体指针访问数据,也可以隐式间接引用

type Coordinate struct {	X int	Y int}func main() {	var p *Coordinate	p = &Coordinate{1, 2}	fmt.Println((*p).X)//通过结构体指针访问	fmt.Println(p.X)//隐式间接访问}

可使用列出字段值的方法来分配结构体,未被分配值的字段为该类型的零值

type Coordinate struct {	X int	Y int}func main() {	var p *Coordinate	p = &Coordinate{X:1}	fmt.Println((*p).X)	fmt.Println(p.Y)}
数组

go中使用 []类型 来声明数组

func main() {	a := [5]int{1,2,3,4,5}	fmt.Println(a)}
切片

数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。
切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:
包含下界不包含上界

func main() {	a := [5]int{1,2,3,4,5}	var p = a[0:4]	fmt.Println(p)}

a[0:4]表示a数组中下标0到3的元素,切片并没有真正意义上存储数据,而只是描述数组中的一段数据,修改切片会修改数组中的对应元素。

func main() {	a := [5]int{1,2,3,4,5}	var p = a[0:3]	var q = a[1:4]	fmt.Println(p)	fmt.Println(q)	p[2] = 9	fmt.Println(p)	fmt.Println(q)}


切片可以省略上下界,下界的默认值的0,上界的默认值为数组的长度
对于数组a [10]int,下面的切片是等价的

a[0:10]a[:10]a[0:]a[:]

切片的长度指存放的元素个数,容量指从切片第一个元素开始到底层数组最后一个元素的个数。

func main() {	s := []int{1, 3, 5, 7, 9, 11}	printSlice(s)	// 截取切片使其长度为 0	s = s[:0]	printSlice(s)	// 拓展长度	s = s[:4]	printSlice(s)	// 舍弃前两个值	s = s[2:]	printSlice(s)	// 拓展长度	s = s[:4]	printSlice(s)}func printSlice(s []int) {	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)}

切片的零值为nil且没有底层数组

func main() {	var s []int	fmt.Println(s, len(s), cap(s))	if s == nil {		fmt.Println("nil!")	}}

切片可以用内建函数make创建,双参数时第二个参数是长度和容量,三参数时第二个是长度,第三个是容量

func main() {	a := make([]int, 5)	fmt.Println(len(a), cap(a))	s := make([]int, 0, 5)	fmt.Println(len(s), cap(s))}


可以通过append向切片追加元素,如果底层数组的容量不够,将创建新的数组,将切片指向新的数组。

func main() {	var language = []string{"Java", "C", "Python"}	fmt.Printf("first element address:%v, len:%d, cap:%d, %v\n",	 &language[0], len(language), cap(language), language)	language = append(language, "Golang", "Scala", "Lua")	fmt.Printf("first element address:%v, len:%d, cap:%d, %v\n",	 &language[0], len(language), cap(language), language)}


for 循环的 range 形式可遍历切片或映射。当使用 for 循环遍历切片时,每次迭代都会返回两个值。第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}func main() {	for i, v := range pow {		fmt.Printf("2**%d = %d\n", i, v)	}}


range也可以将下标或值赋予 _ 来忽略它,当只需要索引时可忽略第二个变量

func main() {	pow := make([]int, 10)	for i := range pow {		pow[i] = 1 << uint(i) // == 2**i	}	for _, value := range pow {		fmt.Printf("%d\n", value)	}}

映射

map 映射将键映射到值。映射的零值为 nil 。nil 映射既没有键,也不能添加键。
make 函数会返回给定类型的映射,并将其初始化备用。

type Person struct {	Weight, Height float64}var m map[string]Personfunc main() {	m = make(map[string]Person)	m["Bill"] = Person{		70, 180,	}	fmt.Println(m["Bill"])}

如果映射的元素类型相同,可以只在外层声明类型

type Person struct {	Weight, Height float64}var m map[string]Personfunc main() {	m = map[string]Person{		"Bill":{70, 180},		"John":{85, 195},	}	fmt.Println(m)}


可以获取修改删除映射元素,也可以使用双赋值检测某个key是否存在

type Person struct {	Weight, Height float64}var m map[string]Personfunc main() {	m = map[string]Person{		"Bill":{70, 180},		"John":{85, 195},		"Mary":{55, 168},	}	fmt.Println(m)	fmt.Println(m["John"])	m["Bill"] = Person{75, 180}	fmt.Println(m)	delete(m, "John")	fmt.Println(m)	param1, ok := m["Jack"]	fmt.Println(param1, ok)	param2, ok := m["Bill"]	fmt.Println(param2, ok)}

go 程

go中提供了轻量级的线程goroutine去执行函数,使用go 函数名执行。

import (	"fmt"	"time")func say(s string) {	for i := 0; i < 5; i++ {		time.Sleep(100 * time.Millisecond)		fmt.Println(s)	}}func main() {	go say("world")	say("hello")}
信道

信道是带有类型的管道,通过make和chan关键字创建信道,通过信道 *** 作符 <- 来发送或者接收值。
信道可以是 带缓冲的。将缓冲长度作为第二个参数提供给 make 来初始化一个带缓冲的信道,
仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。

import "fmt"func sum(s []int, c chan int) {	sum := 0	for _, v := range s {		sum += v	}	c <- sum }func main() {	s := []int{7, 2, 8, -9, 4, 0}	c := make(chan int)	go sum(s[:len(s)/2], c)	go sum(s[len(s)/2:], c)	x, y := <-c, <-c 	fmt.Println(x, y, x+y)}


如果将上述代码改成

func main() {	s := []int{7, 2, 8, -9, 4, 0}	c := make(chan int, 1)	sum(s[:len(s)/2], c)	sum(s[len(s)/2:], c)	x, y := <-c, <-c	fmt.Println(x, y, x+y)}

增加缓冲区同时去掉go程,则发生了锁冲突

Select

select 语句使一个 Go 程可以等待多个通信 *** 作。select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。
当 select 中的其它分支都没有准备好时,default 分支就会执行。为了在尝试发送或者接收时不发生阻塞,可使用 default 分支:

import (	"fmt"	"time")func main() {	tick := time.Tick(100 * time.Millisecond)	boom := time.After(500 * time.Millisecond)	for {		select {		case <-tick:			fmt.Println("tick.")		case <-boom:			fmt.Println("BOOM!")			return		default:			fmt.Println("    .")			time.Sleep(50 * time.Millisecond)		}	}}
Mutex

Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法:Lock Unlock
可以通过在代码前调用 Lock 方法,在代码后调用 Unlock 方法来保证一段代码的互斥执行。

type SafeCounter struct {	v   map[string]int	mux sync.Mutex}// Inc 增加给定 key 的计数器的值。func (c *SafeCounter) Inc(key string) {	c.mux.Lock()	c.v[key]++	c.mux.Unlock()}// Value 返回给定 key 的计数器的当前值。func (c *SafeCounter) Value(key string) int {	c.mux.Lock()	defer c.mux.Unlock()	return c.v[key]}func main() {	c := SafeCounter{v: make(map[string]int)}	for i := 0; i < 100; i++ {		go c.Inc("key")	}	fmt.Println(c.Value("key"))}
总结

以上是内存溢出为你收集整理的Go语言入门全部内容,希望文章能够帮你解决Go语言入门所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1212070.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存