go语言的25个关键字(基础)

go语言的25个关键字

程序声明
1-2 import 导入,package 包(1,文件名和包名不需要一致,包名约定使用小写字符。2,一个go包里面的多个文件必须使用相同的包名,一个包里面的go文件就相当于一个go文件,这些文件里函数和变量可以互相调用,不用大写。根目录下不管有几个go文件,都可以写包main ,尽量在根目录下创建mod文件,这样就可以mod模块名/包名。3,一个包就是一个文件夹。4,包名导入的是默认名称,可以起别的名字覆盖默认名称,import by “bytes”)
程序实体的定义和声明
3 chan 通道(就是因为channel,才让go语言不同于其他语言,channel理解为消息队列,先进先出,创建channel有一下几种形式,
下面展示一些 创建channel

var ch chan string; // nil channel
ch := make(chan string); // zero channel
ch := make(chan string, 10); // buffered channel
//channel里面的value buffer的容量也就是channel的容量。channel的容量为零表示这是一个阻塞型通道,非零表示缓冲型通道[非阻塞型通道]。

//但是,这里有个坑,当channel的容量为0时,for循环一次开10个goroutine打印输出,此时理论上应该是顺序输出的,但是确实无序输出的,这是因为现在的 Go 默认就是启用的多核,不像以前版本还需要手动设置使用多核。


4 var 变量控制(var是最基本的定义变量的方法,有时也会用到:=来简短声明定义变量,限制条件:只能用在函数内部,不能在函数外部,定义全局变量还得是var)
代码示例:下面展示一些 var基本用法

// 定义变量
var name string 
//定义变量并初始化值
var name string="zoffan"
//同时初始化多个同类的变量
var name1,name2,name3 string="name1","name2","name3"
//省略变量类型
var name1,name2,name3="name1","name2","name3"
//同时初始化多个不同类型的变量
var(
name  string="zoffan"
count int =2
)

5 const 常量声明,任何时候const都可以和var同时出现。
6 func 定义函数和方法(1,可以定义多个返回值,go语言的返回值是在栈里面的,c语言是rax寄存器中,rax寄存器只有一个,所以只能返回一个值。2,函数是可变参的,变参本质上是slice,变参只能有一个,而且必须是最后一个,下面展示一些 变参函数

// 
func test(s string ,n ...int)string{
var x int
for _,i:=range n{
x+=i
return fmt.Sprintf(s,x)
}
}


7 interface 定义接口(interface是一种具有一组方法的类型,这些方法定义了interface的行为。如果说一个类型实现了一个interface的所有方法,我们就说该类型实现了改interface,所以所有类型都实现空interface。因为任何一种类型至少实现了0个方法,go没有显示的关键字来实现interface,只需要实现interface包含的方法即可
下面展示一些 interface

// An highlighted block
type Dog interface {
  Category()
}

type Ha struct {
  Name string
}
//这里称为方法,不再称为函数,方法是专门属于某一个对象的
func (h Ha) Category() {
  fmt.Println("狗子")
}

func main() {
  h := Ha{"二哈"}
  h.Category()
  test(h)
}

func test(a Dog) {
  fmt.Println("成功调用啦")
}
//test函数接受Dog类型,但是我们传入的是Ha类型的h,但是可以正常运行,说明Ha类型已经成功实现了Dog。
//struct可以嵌入,接口也是可以嵌入的,
type Dog interface {
  Animal
}

type Animal interface {
  Category()
}

type Ha struct {
  Name string
}

func (h Ha) Category() {
  fmt.Println("狗子")
}

func main() {
  h := Ha{"二哈"}
  h.Category()
  test(h)
}

func test(a Dog) {
  fmt.Println("成功调用啦")
}
//类型断言,一个interface被多种类型实现时,那么我们就要区分interface的变量究竟存储哪种类型的值,go 可以使用 comma, ok 的形式做区分 value, ok := em.(T):em 是 interface 类型的变量,T代表要断言的类型,value 是 interface 变量存储的值,ok 是 bool 类型表示是否为该断言的类型 T。。
type Dog interface {
	Animal
}

type Animal interface {
	Category()
}

type Ha struct {
	Name string
}

func (h Ha) Category() {
	fmt.Println("狗子")
}

func main() {
	h := Ha{"二哈"}
	h.Category()
	test(h)
}

func test(a Dog) {
	if v, ok := a.(Ha); ok {
		fmt.Println(v.Name)
	}
}
//如果需要区分很多种类型,就可以使用switch断言,这种断言方式只能在switch中使用
type Dog interface {
	Animal
}

type Animal interface {
	Category()
}

type Ha struct {
	Name string
}

func (h Ha) Category() {
	fmt.Println("狗子")
}

func main() {
	h := Ha{"二哈"}
	h.Category()
	test(h)
}

func test(a Dog) {
	switch v := a.(type) {
	case Ha:
		fmt.Println(v.Name)
	default:
		fmt.Println("暂未匹配到该类型")
	}
}
//空接口
//空接口 interface{} 没有任何方法签名,也就意味着任何类型都实现了空接口。其作用类似于面向对象语言中的根对象 Object 。

func Print(v interface{}) {
  fmt.Println(v)
}

func main() {
  Print(1)
  Print("Hello, World")
}
// 输出结果为:1  Hello, World
//既然空的 interface 可以接受任何类型的参数,那么一个 interface{}类型的 slice 是不是就可以接受任何类型的 slice ?

func printAll(vals []interface{}) { //1
	for _, val := range vals {
		fmt.Println(val)
	}
}
func main(){
	names := []string{"stanley", "david", "oscar"}
	printAll(names)
}
//执行之后竟然会报 cannot use names (type []string) as type []interface {} in argument to printAll 错误,why?

//这个错误说明 go 没有帮助我们自动把 slice 转换成 interface{} 类型的 slice,所以出错了。go 不会对 类型是interface{} 的 slice 进行转换 。

//但是我们可以手动进行转换来达到我们的目的。

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
	interfaceSlice[i] = d
}
//如果是按 pointer 调用,go 会自动进行转换,因为有了指针总是能得到指针指向的值是什么,如果是 value 调用,go 将无从得知 value 的原始值是什么,因为 value 是份拷贝。go 会把指针进行隐式转换得到 value,但反过来则不行。


8 map 字典/map(键值对)
9 struct 定义数据类型(
1,顺序初始化必须包含全部字段,否则会报错。2,支持匿名结构,可用作结构成员或者定义变量,支持==,
!=相等操作符,可以用作map键类型。 struct支持嵌入式结构,可以像普通字段那样访问匿名字段成员,
下面展示一些 嵌入式结构体

// 想被结构体外的函数调用,那这个变量的名字都必须大写开头
type Person struct{
Name string
}
type User struct{
Person
Age int
}
func main(){
u:=User{
Perosn:Person{
Name:"ckl"
},
Age:22,
}
fmt.Println(u.name)

}

)
10type 声明类型
程序流程控制
11 for (for 是go中唯一的循环结构,for循环有三种基本使用方式,
下面展示一些 for使用

// 1,带一个循环条件,
i := 1
for i <= 3 {
  fmt.Println(i)
  i = i + 1
}
//最经典的
for j := 7; j <= 9; j++ {
  fmt.Println(j)
}
//不带条件,一直for循环,直到遇到break或return来跳出循环
for {
  fmt.Println("loop")
  break
}


)
12 break 终止
13 continue 继续下一次循环
14 select 选择流程(可以同时等待多个通道操作,将协程(goroutine),通道(channel)和select结合起来构成Go语言的一个强大特性
下面展示一些 组合

package main

import "time"
import "fmt"

func main() {

  // 本例中,我们从两个通道中选择
  c1 := make(chan string)
  c2 := make(chan string)

  // 为了模拟并行协程的阻塞操作,我们让每个通道在一段时间后再写入一个值
  go func() {
    time.Sleep(time.Second * 1)
    c1 <- "one"
  }()
  go func() {
    time.Sleep(time.Second * 2)
    c2 <- "two"
  }()

  // 我们使用select来等待这两个通道的值,然后输出
  for i := 0; i < 2; i++ {
    select {
    case msg1 := <-c1:
      fmt.Println("received", msg1)
    case msg2 := <-c2:
      fmt.Println("received", msg2)
    }
  }
}


15 switch (下面展示一些 内联代码片

// sExpr和expr1、expr2、expr3的类型必须一致。Go的switch非常灵活,表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项;而如果switch没有表达式,它会匹配true。 Go里面switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case,而是跳出整个switch
switch sExpr {
  case expr1:
      some instructions
  case expr2:
      some other instructions
  case expr3:
      some other instructions
  default:
      other code
}


16 case
17 default
18 defer 用于资源的释放,会在函数返回之前进行调用,(1,比如说打开一个文件要关闭,
下面展示一些 defer使用的代码

// 文件关闭
func test(){
f,err:=os.Open(filename)
defer f .Close()
if err!=nil{
panic(err)
}
}

2,如果有多个defer表达式,调用顺序类似于栈,后入先出,越后面的defer越是先被调用
下面展示一些 defer

// An highlighted block
func test(){
defer fmt.Println(1)
defer fmt.Println(2)
}
//输出的结果为
 2
 1

3,defer和return使用起来很容易乱套,这里多举几个例子
下面展示一些 defer+return
//函数的返回不是一个原子调用,其实是两步 :1返回值赋值,2返回 。那么这时候就出现了defer表达式出现在函数返回值之后,返回之前,把返回值给修改了。导致返回值与想象的不一样。
小窍门,使用defer的时候把return语句拆成两句写:返回值 defer和return三者之间的执行顺序
1,返回值=xxx
2,调用defer函数
3,空的return

// 例子1
func main(){
i:=f()
fmt.Printfln(i)
}
func f()(result int){
defer func(){//闭包函数是地址引用,go中不多的传引用
result++
}()
return 0
}
//分析  
//例子1返回的结果是1,通过main函数里面调用并且输出,下面两个就不写main函数了。0就是给reslut变量,但是中间调用了一次defer,导致result被操作改变了,所以返回的不是0。因为return 0,所以接收返回值的reslut=0;执行defer,闭包函数自动执行,对reslut进行了++,导致result变成1。最后返回。
1,reslut=0;
2,func()
3,return

//例子2
func f() (r int){
t:=5
defer func(){
t=t+5
}()
return t
}
//解析 分3步写,最终的返回结果是5
// 先找到返回值,对其进行赋值 r=5
//在执行defer                func(),虽然闭包函数是地址引用,但是他改变的是t,r我们已经赋值了,不会在改变了
//返回                       return


//例子3
func f()(r int){
defer func(r int){//这里改的r是传值引用的r,跟上面不一样,不是传地址引用了
r=r+5
}(r)
return 1
}
//解析  最终返回结果是1,闭包函数是传值引用,从形式上看,所有的匿名函数都是闭包,闭包的创建方式和普通函数几乎一致,只有一个关键区别,闭包函数没有名字。我也很迷糊,我理解:闭包函数就是能够读取其他函数内部变量的函数,一个函数内部的子函数,闭包可以理解为“定义在一个函数内部的函数”,只有函数内部的子函数才能读取局部变量,在本质上闭包就是将函数内部和函数外部连接起来的一座桥梁,闭包的用途,可以读取函数内部的变量,让这些变量的值始终保持在内存中(外部函数执行完就没了)。闭包是解决局部变量不能被外部访问的一种解决方案,是把函数当做返回值得一种应用。总体思想为:在函数内部定义局部变量,把另一个函数当作返回值,局部变量对于返回值函数就相当于全局变量,所以多次调用返回值函数局部变量的值跟随变化。在go语言中函数参数都是以复制的方式(不支持以引用的方式)传递,特殊的就是闭包函数,闭包函数对外部变量是以引用的方式传递。引用类型作为参数,称为浅拷贝,值类型作为参数,称为深拷贝。在go中如果希望值类型的实参跟随形参变化,可以把值类型的指针作为参数,func demo(i * int, s string){*i=5},调用的时候m:=1   demo(&m,s)..go语言中有5个引用类型的变量,其他都是值类型,slice, map,channel,interdface,func().
//如果把例子3改一下,这个时候输出的就是6了
func f()(r int){
defer fun(){
r=r+5
}()
return 1
}

19 if (这里要注意:1,可省略条件表达式的括号。
2,支持初始化语句,可定义代码块局部变量。
3,代码块左大括号必须在条件表达式尾部。
4,不支持三元操作符 “a > b ? a : b”)
20 else
21 go(golang通过goroutine实现高并发,go关键字是开启goroutine的钥匙,go 函数名())
22goto,尽量别用
23fallthrough (1,会直接执行紧跟的够一个case或者default语句,无论条件是否满足都会执行2,如果加入fallthrough,紧跟的后一个case条件不能定义常量或者变量3,fallthrough不一定在一个条件的最后一行,写到中间行,只要执行了fallthrough就会跳到下一个条件语句,本条件后面的语句不执行,直接跳走)
24 range 遍历读取slice map channel数据
25 return 用于从函数返回
前面这25个叫关键字,还有一些声明的常量,类型和函数
常量:true false iota nil

类型:int (int如果在32位系统上是4个字节,在64位系统上是8个字节) int8 int16 int32(在哪都是4个字节) int64(在哪都是8个字节)

       uint     uint8    uint16   uint32   uint64    uintptr

       float32   float64    complex128      complex64

       bool     byte     rune      string    error

函数: make len cap new append copy close delete

        complex     real    imag

        panic      recover
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值