• go语法入门1


    语法基础

    注释

    // 单行注释
    /* xxxx */ 编译器忽略该区间,其间都被认为是注释内容。虽然Go支持,但很少使用,一般都用多行//

    //包注释
    package main
    
    import "fmt"
    
    /*
    x int
    y int
    */
    
    // x int
    // y int  多行注释
    
    func main() {
    	fmt.Println("zzzz")	 //打印
    	//TODO: 将来完成,一把是这个任务没写完,加入这个注释,方便下次继续完成这个任务	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    // TODO: 将来完成,推荐
    // NOTE: 请注意
    // Deprecated: 告知已经过期,建议不要使用。未来某个版本可能移除
    
    • 1
    • 2
    • 3
    • 函数、结构体等习惯把注释写在上面
    • 包注释会写在package之上

    命名规范

    • 标识符采用CamelCase驼峰命名法
      如果只在包内可用,就采用小驼峰命名
      如果要在包外可见,就采用大驼峰命名

      userName 小驼峰命名  首字母小写中间大写 
      UserName 大驼峰 首字母大写 中间大写   区别在与包外可见
      user_name snake 蛇形命名
      
      • 1
      • 2
      • 3
    • 简单循环变量可以使用i、j、k、v等

      一般用简单的英文单词
      
      • 1
    • 条件变量、循环变量可以是单个字母或单个单词,Go倾向于使用单个字母。Go建议使用更短小

    • 常量驼峰命名即可
      在其他语言中,常量多使用全大写加下划线的命名方式,Go语言没有这个要求
      对约定俗成的全大写,例如PI

    • 函数/方法的参数、返回值应是单个单词或单个字母

    • 函数可以是多个单词命名

    • 类型可以是多个单词命名

    • 方法由于调用时会绑定类型,所以可以考虑使用单个单词

    • 包以小写单个单词命名,包名应该和导入路径的最后一段路径保持一致

    • 接口优先采用单个单词命名,一般加er后缀。Go语言推荐尽量定义小接口,接口也可以组合

    关键字

    25个关键字

    break     default    	func     interface   select
    case      defer      	go        map        struct
    chan      else       	goto     package     switch
    const     fallthrough   if       range        type
    continue  for           import    return    var
    
    • 1
    • 2
    • 3
    • 4
    • 5

    标识符

    • 一个名字,本质上是个字符串,用来指代一个值

    • 只能是大小写字母、数字、下划线,也可以是Unicode字符

      Unicode字符也可以是中文 但是不推荐标识符采用中文的字符
      
      • 1
    • 不能以数字开头

    • 不能是Go语言的关键字

      不能和关键字冲突
      
      • 1
    • 尽量不要使用“预定义标识符”,否则后果难料

    • 大小写敏感

    字面常量

    它是值,不是标识符,但本身就是常量,不能被修改。
    Go语言中,boolean、rune、integer、float、complex、string都是字面常量。其中,rune、
    integer、float、complex常量被称为数值常量。

    100
    0x6162 0x61_62_63
    3.14
    3.14e2
    3.14E-2
    
    '测'								//字符 ''单引号中  有且仅有一个
    '\u6d4b'
    '\x31'
    '1'
    '\n'
    "abc" "\x61b\x63"				// 字符串  ""双引号中,可以有一个也可以多个
    "测试" "\u6d4b试"
    "\n"
    
    
    true
    false
    iot
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ‘1’ "1"的区别

    ‘1’ 这个代表有且只有一个数字就是1 代表的是字符

    “1” 这个代表和这个字符串里有1 代表的是字符串

    常量

    常量:使用const定义一个标识符,它所对应的值,不允许被修改。
    对常量并不要求全大写加下划线的命名规则。

    • 常量必须在定义是赋值,并且后面不能再变化

    • 数组不能赋值给常量

      const 常量名 = 初值 常量必须在定义是直接赋初值
      
      package main
      import "fmt"
      
      func main() {
      	const a int = 100 // 指定类型定义常量并赋值
      	const b = "abc"   // 定义常量,等式左边未给出类型,将进行类型推导
      	const c = 12.3
      	const d = 'T'
      	fmt.Printf("%T\n", a)
      	fmt.Printf("%T\n", b)
      	fmt.Printf("%T\n", c)
      	fmt.Printf("%T\n", d)
      }
      
      int					%T 输出值对应的类型
      string
      float64
      int32
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      批量定义

      const (
      		c    = "abc" // 类型推导    String类型
      		d    = 100   // 字面常量 无类型常量100 关联, 默认推导int类型
      		e uint8 = 100   // 无类型常量100 ,和左边有类型常量uint8类型 e
      		// int 8bits => 1bytes -128~127 0~255
      		f float32 = 1.5       //flost32类型
      		g         = true     //bool类型
      	)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    变量

    • 变量:赋值后,可以改变值的标识符。
    • 建议采用驼峰命名法。
    package main
    
    import "fmt"
    
    func main() {
    	var a // 错误,无法推测类型
    	var b int // 正确,只声明,会自动赋为该类型的零值
    	var c, d int // 正确,声明连续的同类型变量,可以一并声明,会自动赋为该类型的零值
    	var b = 200 // 错误,b多次声明,第二行已经声明过
    	b = 200 //正确
    	var f, e int = 11, 22 // 正确
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    // 用var声明,立即赋值,或之后赋值
    var b int // 正确,只声明,会自动赋为该类型的零值
    b = 200
    b = 300
    b = "4" // 错误,类型错误
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    var a = 100 // 右边无类型常量,缺省类型是int,左边a没有指定类型,用到类型推导,所以a为int类型 var a int = 100
    var a // 错误的,因为没有右边,go是强类型语言,此时不能利用右边来推导,左边又没有指定类型,所以错误
    var a int // 正确,指定了类型,但是没有赋值。go中正确的原因是 零值可用。int的零值是0
    var a int32 = 200 // 正确,指定了类型,也赋值。不会采用类型推导

    // 批量赋值
    var a int, b string // 错误,批量不能这么写
    var ( // 正确
      a int
      b string
    )
    
    var ( // 错误,变量必须有类型,但没有给类型,也不能使用值来推导类型
      a
      b
    )
    
    var a int, b string = 111, "abc" // 错误,多种类型不能这么写,语法不对
    var (
      a int   = 111
      b string = "abc"
    ) // 正确,建议批量常量、变量都这么写
    var (
      a = 111
      b = "abc"
    ) // 正确,类型推导
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    变量:标识符的指向的值建立后,可以改变

    • 类型也可以变,往往动态语言JS、Python,举例 a = 100, a=“abc”, a=[1,2,3]
    • 同类型可以变
    • 批量定义 必须给定类型或者赋值,但是常量可以不用定义类型,因为常量在定义的时候必须给定一个值,因此可以进行类型推到
    短格式
    a := 100 // 赋值语句,短格式变量定义语句,定义变量。定义了变量标识符a,右边可以用来推导a的类型为int
    相当于 var a = 100 同样的 没有定义类型 通过字面量来推导a的类型
    
    • 1
    • 2

    不可以重复定义类型

    var a int //零值0  
    a := 100 //错误的  因为前面已经定义类型了  短格式在定义类型是不允许的	
    
    • 1
    • 2

    有特例:

    var a int
    a,b := 123,"abcd"  //竟然可以?在这里a不能重新定义为新类型,a被检测到了,go语言上只能迁就你了,但是要求a同类型,b是新定义的
    
    • 1
    • 2

    短格式要求:

    a, b := 123, "abcd"
    a, b, c := 123, "abcd", 12.5 // 短格式批量同一行定义,因为短格式不能指定类型,所以采用类型推导,左右要求个数一致
    
    • 1
    • 2

    短格式
    使用 := 定义变量并立即初始化
    只能用在函数中,不能用来定义全局变量
    不能提供数据类型,由编译器来推断

    交换

    go的数据交换是特殊的 具体的特殊就是在定义和赋值后,想相当于对变量名进行了快照的处理,在交换数据时,是直接调用快照前,变量指向的数值

    package main
    
    import "fmt"
    
    func main() {
    	a := 100
    	b := 200
    	a, b = b, a  //按照别的语言当a=b时,a=200了,后面的b=a肯定是调用的是a=200,但是go不是,go依旧调用的是前面a=100,相当于是快照了
    	fmt.Println(a, b) 
    
    }
    
    [Running] go run "f:\goprpject\test2\m.go"
    200 100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    iota

    //一定是批量定义const这种,如果是单行 iota一直都是0

    // iota 定义成批常量,iota从0,从成批的第一行

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	const (
    		a = iota    //第一行为0
    		b			// 1	
    		c			// 2
    	)
    	fmt.Println(a, b, c)
    }
    0 1 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	const (
    		a = iota + 1 // 1   
    		b            // 2  批量定义的时候,下面一行可以继承上面的表达式 b = iota +1
    		c			// c = iota + 1   iota=2  c=3 
    		_ // 空白标识符,黑洞 _=iota+1    iota =4
    		d      
    		t = 100
    		_
    		_
    		e // ? e=100    //批量定义的时候,下面一行可以继承上面的表达式 
    	)
    	fmt.Println(a, b, c, d, t, e)
    }
    1 2 3 5 100 100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    	const (
    		m = 100   // iota:0
    		n // n : 100, iota : 1
    		a = iota * 2  // 2 * 2
    		b = iota * 2  // 3 * 2
    		c
    		d
    	)
    	fmt.Println(a, b, c, d) // 4 6 8 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    总结:iota只能用于常量,是在成批定义和序列有关的常量定义,iota在成批定义中,可以认为是行索引,可以应用为日期和月份

    索引和序号的区别:序号一般是从1开始的,行索引一般从0开始

    零值

    变量已经被声明,但是未被显式初始化,这是变量将会被设置为零值。其它语言中,只声明未初始化的变量误用非常危险,但是,Go语言却坚持“零值可用”理念。在Go语言中合理利用零值确实带来不小的便利

    • int为0
    • float为0.0
    • bool为false
    • string为空串""(注意是双引号)
    • 指针类型为nil
    • 其它类型数据零值,学到再说

    标识符本质

    *每一个标识符对应一个具有数据结构的值,但是这个值不方便直接访问,程序员就可以通过其对应的标识符来访问数据,标识符就是一个指代。一句话,标识符是给程序员编程使用的。*标识符就是给人来看的,经过机器编译后,就是以内存地址的形式存在。

    标识符写源代码时候,用来指代某个值的。编译后还有变量、常量标识符吗? 没有了,因为数据在内存中,内存访问靠什么?地址,标识符编译后就没有了就换成了地址了。

    源代码本质是文本文件
    编译 ,源代码编程成二进制可执行文件。运行这个磁盘上的二进制可执行文件,运行在当前OS上,变成进程,变量、常量、值在这块内存中放着

    变量可见性

    包级标识符

    在Go语言中,在.go文件中的顶层代码中,定义的标识符称为包级标识符。如果首字母大写,可在包外可见。如果首字母小写,则包内可见。

    在a.go的文件中
    package main
    
    // 无类型常量定义
    var a = 20   // int
    var b = 3.14 // float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    在m.go的文件中
    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(a, b)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用建议

    • 顶层代码中定义包级标识符首字母大写作为包导出标识符,首字母小写作为包内可见标识符
    • const定义包级常量,必须在声明时初始化
    • var定义包级变量
      可以指定类型,也可以使用无类型常量定义
      延迟赋值必须指定类型,不然没法确定零值
    • 有相关关系的,可以批量定义在一起
    • 一般声明时,还是考虑“就近原则”,尽量靠近第一次使用的地方声明
    • 不能使用短格式定义
    局部标识符

    定义在函数中,包括main函数,这些标识符就是局部标识符。

    使用建议

    • 在函数中定义的标识符

    • const定义局部常量

    • var定义局部变量

      可以指定类型,也可以使用无类型常量定义
      延迟赋值必须指定类型,不然没法确定零值

    • 有相关关系的,可以批量定义在一起

    • 在函数内,直接赋值的变量多采用短格式定义

    布尔型

    类型bool,定义了2个预定义常量,分别是true、false。

    bool在go中不是int类型,也不是其他整数类型。在go中,bool就是布尔型,和整型没有关系,就是完全不同的类型。

    数值型

    整型

    • 长度不同:int8、int16(C语言short)、int32、int64(C语言long)

    • 长度不同无符号:uint8、unit16、uint32、uint64

      • byte类型,它是uint8的别名
    • 自动匹配平台:int、uint

      • int类型它至少占用32位,但一定注意它不等同于int32,不是int32的别名。要看CPU,32位就是4字节,64位就是8字节。但是,也不是说int是8字节64位,就等同于int64,它们依然是不同类型!

      以上类型均不相同,但是独立的类型

      package main
      
      import "fmt"
      
      func main() {
      	var a = 20
      	b := 30
      	var c int = 40
      	fmt.Printf("%T, %T, %T, %d\n", a, b, c, a+b+c)
      }
      int, int, int, 90
      
      
      看区别
      
      package main
      
      import "fmt"
      
      func main() {
      	var a = 20
      	b := 30
      	var c int = 40
      	fmt.Printf("%T, %T, %T, %d\n", a, b, c, a+b+c)
      	var d int64 = 50
      	fmt.Printf("%T, %T\n", d, a+d)  // a是int类型  d是int64  不是一个类型 必须同类型才能相加
      }
      
      
      package main
      
      import "fmt"
      
      func main() {
      	var a = 20
      	b := 30
      	var c int = 40
      	fmt.Printf("%T, %T, %T, %d\n", a, b, c, a+b+c)
      	var d int64 = 50
      	fmt.Printf("%T, %T\n", d, a+int(d))
      }
      int64, int   //d是int64  将强制类型转换为int类型
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43

      %d 数值形式,往往用于整数

      %T 表示type,取值的类型

    强制类型转换

    把一个值从一个类型强制转换到另一种类型,有可能转换失败。

    package main
    import "fmt"
    func main() {
    var d int64 = 50
    fmt.Printf("%T, %d\n", d, d)
    fmt.Printf("%T, %s; %T, %d; %T, %f\n", string(d), string(d), rune(d),
    rune(d), float32(d), float32(d))
    }
    输出如下
    int64, 50
    string, 2; int32, 50; float32, 50.000000
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    %T 表示type,取值的类型
    %d digital 数值形式,往往用于整数
    %s 用string类型的值
    %q 带字符串类型引号的%s,quote引号
    %c character,字符输出
    %f float浮点数输出,默认精度为6

    字符和整数

    字符表达,必须使用单引号引住一个字符。

    单引号留给了表示字符,字面量表达,本质上是int32(rune)或byte(uint8)

    双引号和反引号用来表示字符串字面量。

    type rune = int32 // rune是int32的别名,4个字节,可以是Unicode字符
    type byte = uint8 // byte是uint8的别名,1个字节
    
    • 1
    • 2
    package main
    
    import "fmt"
    
    func main() {
    	var c rune = '中'                     // 字符用单引号
    	fmt.Printf("%T, %[1]c, %[1]d\n", c)   // int32, 中, 20013
    }
    [1] 代表的是指定后面的序号
    
        c = 'a'
        fmt.Printf("%T, %c, %d\n", c, c, c) // int32, a, 97
    
    	var d byte = '中' // 错误,超出byte范围  byte是1个字节 但是中是四个字节的  转换出来超出byte的范围
    	
    	
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    浮点数

    float32:最大范围约为3.4e38,通过math.MaxFloat32查看
    float64:最大范围约为1.8e308,通过math.MaxFloat64查看
    打印格式化符常用%f

    // fmt的格式化,参考包帮助 https://pkg.go.dev/fmt
    f := 12.15
    fmt.Printf("%T, %f\n", f, f) // 默认精度6
    fmt.Printf("%.3f\n", f)    // 小数点后3位
    fmt.Printf("[%3.2f]\n", f)  // 宽度撑爆了,中括号加上没有特殊含义,只是为了看清楚占的
    打印宽度
    fmt.Printf("[%6.2f]\n", f)  // 宽度为6,保留两位小数
    fmt.Printf("[%-6.2f]\n", f)  // 左对齐
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    python: float64与float32转换、压缩比较与转换偏差
    计算机组成原理--------12.4---------开始
    【spring-05】BeanFactory 后处理器
    数据结构——线索二叉树(TBT)
    Support for password authentication was removed on August 13, 2021 解决方案
    黑客技术-小白自学
    媒体报道 | 亿美软通以诚信之心 守护信息安全
    电脑换cpu要重装系统吗
    myql的三种删除方式:delete truncate drop
    数据中台不是万能钥匙,企业需求才是数据中台建设的根本
  • 原文地址:https://blog.csdn.net/xiaolong1155/article/details/133532026