Go 基础语法

Package 包

main包是程序入口,每个程序只有一个main包

导包的两种方式:

  • 打包导入
import (
	"fmt"
	"math"
)
  • 多语句导入
import "fmt"
import "math"

导出名:

​ 大写的方法名为导出名,小写不是。

标记

行分隔符

  • 在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
  • 如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法

注释

  • 注释不会被编译,每一个包应该有相关注释。
  • 单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 / 开头,并以 / 结尾。

标识符

  • 标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(AZ和az)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

关键字

下面列举了 Go 代码中会使用到的 25 个关键字或保留字:

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

函数

  • 分开写参数类型:
func add(x int,y int) int {
	return x + y
}
  • 相同参数类型:
func add(x ,y int) int {
	return x + y
}
  • 多返回值
func addAndSub(x int, y int) (int, int) {
	var add = x + y
	var sub = x - y
	return add, sub
}
  • 命名返回值
func split(num int) ( /*十位数*/ dig2 /*个位数*/, dig1 int) {
	dig1 = num * 4 / 9
	dig2 = num - dig1
	return dig2, dig1
}

函数定义用func关键字 ,可以有多个参数,写法类似C(参数名 参数类型),返回值类型写在参数后面

数据类型

序号类型和描述
1布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
2数字类型 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。
3字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。
4派生类型: 包括:(a) 指针类型(Pointer)(b) 数组类型© 结构化类型(struct)(d) Channel 类型(e) 函数类型(f) 切片类型(g) 接口类型(interface)(h) Map 类型

变量

定义变量

使用var关键字定义变量,并初始化。

var name string = innerpeacez

定义多个变量(这种结构一般用于定义全局变量)

var (
	v1 = 10
	v2 = 20
)

短声明变量

name := innerpeacez

使用:=符号,简洁的声明变量并赋值,:=不可以使用再函数(func)之外。函数外的每一个语句必须以关键字开始(var,func等)

基本变量类型

Go 也有基于架构的类型,例如:int、uint 和 uintptr。

序号类型和描述
1uint8 无符号 8 位整型 (0 到 255)
2uint16 无符号 16 位整型 (0 到 65535)
3uint32 无符号 32 位整型 (0 到 4294967295)
4uint64 无符号 64 位整型 (0 到 18446744073709551615)
5int8 有符号 8 位整型 (-128 到 127)
6int16 有符号 16 位整型 (-32768 到 32767)
7int32 有符号 32 位整型 (-2147483648 到 2147483647)
8int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)

浮点型:

序号类型和描述
1float32 IEEE-754 32位浮点型数
2float64 IEEE-754 64位浮点型数
3complex64 32 位实数和虚数
4complex128 64 位实数和虚数

其他数字类型

以下列出了其他更多的数字类型:

序号类型和描述
1byte 类似 uint8
2rune 类似 int32
3uint 32 或 64 位
4int 与 uint 一样大小
5uintptr 无符号整型,用于存放一个指针
bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 的别名

rune // int32 的别名
     // 代表一个Unicode码

float32 float64

complex64 complex128

基本类型零值(默认值)

在这里插入图片描述

类型转换

表达式 T(v) 将值 v 转换为类型 T

var _int int = 10
var _float float64 = float64(_int)
var _uint uint = uint(_float)

_int2 := 10
_float2 := float64(_int2)
_uint2 := uint(_float2)

_int3 := 10
_float3 := _int3
_uint3 := _float3

类型推断

在定义一个变量但不指定其类型时(使用没有类型的 var:= 语句), 变量的类型由右值推导得出。

变量作用域

Go 语言中变量可以在三个地方声明:

  • 函数内定义的变量称为局部变量:作用域只在函数体内,参数和返回值变量也是局部变量。
  • 函数外定义的变量称为全局变量: 可以在整个包甚至外部包(被导出后)使用
  • 函数定义中的变量称为形式参数: 形式参数会作为函数的局部变量来使用

常量

普通常量

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

常量不能使用 := 语法定义。未指定类型的常量,由上下文类型推断决定其类型。

import "fmt"

const Pi = 3.141592653

func main() {
   const HelloWorld = "你好,世界"
   // PI = 1234,常量无法修改左值
   fmt.Println(Pi)
   fmt.Println(HelloWorld)
}

定义多个常量

const (
	Name = "innerpeacez"
	Age  = 14
)

特殊常量iota

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

const (
    a = iota // 0
    b        // 1
    c        // 2
)

运算符

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 其他运算符

算术运算符

运算符描述
+相加
-相减
*相乘
/相除
%求余
++自增1
自减1

关系运算符

运算符描述
==检查两个值是否相等,如果相等返回 True 否则返回 False。
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。

逻辑运算符

运算符描述
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。

位运算符

运算符描述
&按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。
|按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或
^按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。
<<左移运算符"<<“是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<“左边的运算数的各二进位全部左移若干位,由”<<"右边的数指定移动的位数,高位丢弃,低位补0。
>>右移运算符">>“是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数。

例如:

pqp & qp | qp ^ q
00000
01011
11110
10011

赋值运算符

运算符描述
=简单的赋值运算符,将一个表达式的值赋给一个左值
+=相加后再赋值
-=相减后再赋值
*=相乘后再赋值
/=相除后再赋值
%=求余后再赋值
<<=左移后赋值
>>=右移后赋值
&=按位与后赋值
^=按位异或后赋值
|=按位或后赋值

其他运算符

运算符描述
&返回变量内存地址
*指针变量,即实际值

运算符优先级

优先级由高到低

优先级运算符
7^ !
6* / % << >> & &^
5+ - | ^
4== != < <= >= >
3<-
2&&
1||

for循环

go中只有一种循环结构----for循环,不能使用(),必须有{}

sum := 0
for i := 0; i < 10; i++ {
   sum += i
}
fmt.Println(sum)

没有前置和后置的for,相当于java中的while

sum := 0
for sum < 100 {
   sum += sum
}
fmt.Println(sum)

死循环(省略了循环条件)

for {
}

if判断

不能使用(),必须有{},其他和java相似

x := 0
if x < 100 {
    fmt.Print("x 小于100")
}

goif在执行前可以执行一个简单的语句,执行语句与判断条件之间用;隔开,执行语句的作用域为当前if

if y := 500; y > 100 {
   fmt.Println("y 大于100")
}

同样也可以有if..else...

switch语句

switch执行顺序,从上到下,满足条件则停止

today := time.Now().Weekday()

switch time.Saturday {
case today:
   fmt.Println("今天")
case today + 1:
   fmt.Println("明天")
case today + 2:
   fmt.Println("后天")
default:
   fmt.Println("好多天后")
}

没有条件的语句,可以在case代码块写条件,这要就可以执行多条件

t := time.Now()
switch {
case t.Hour() < 12:
   fmt.Println("Good morning!")
case t.Hour() < 17:
   fmt.Println("Good afternoon.")
default:
   fmt.Println("Good evening.")
}

defer语句

defer 语句会延迟函数的执行直到上层函数返回。

延迟调用的参数会立刻生成,但是在上层函数返回前函数都不会被调用。

延迟的函数调用被压入一个栈中。当函数返回时, 会按照后进先出的顺序调用被延迟的函数调用。

func main() {
   defer fmt.Println("world")
   fmt.Println("hello")
}

指针

Go语言中存在指针,指针保存了变量的内存地址。但是Go语言中不支持指针运算。go语言中支持多层指针(指向指针的指针)。

func main() {

   i := 100

   // & 符号会生成一个指向其作用对象的指针。也就是底层的内存地址
   p := &i

   fmt.Println(p)
   // * 符号表示指针指向的底层的值。
   fmt.Print(*p)
    
   *p = 1000
   fmt.Print(*p)
   fmt.Println(i)
}

注意:

  • & 返回相应变量的内存地址。
  • * 符号表示指针的具体值。

结构体

  • 结构体(struct)就是一个字段的集合。
  • 结构体字段使用点号来访问。
func main() {
   fmt.Println(Var{1, 2})

   _var := Var{1, 2}
   X := _var.X
   Y := _var.Y
   fmt.Println(X)
   fmt.Println(Y)
}

结构体也可以使用指针

_var2 := Var{1, 2}

q := _var2  // 将_var2的值赋值给q
p := &_var2 // p指向_var2

q.X = 2

p.Y = 3
fmt.Println(q)
fmt.Println(p)
fmt.Println(_var2)
fmt.Println(*p)

结构体文法

v1 = Vertex{1, 2}  // 类型为 Vertex
v2 = Vertex{X: 1}  // Y:0 被省略
v3 = Vertex{}      // X:0 和 Y:0
v4 = &Vertex{1, 2} // 类型为 *Vertex

数组

数组的长度不可改变,如java一样,go语言中也支持多维数组(如:二维数组)

定义数组

func main() {

   var arr [2]int
   arr[1] = 10
   arr[0] = 20

   fmt.Println(arr)
}

初始化数组

var arr = [2]int{10,20}
var arr = [...]int{10,20}

切片Slice

go语言中的切片是对数组的抽象。长度可以改变,切片类似于动态数组

定义切片(未指定容量)

var slice_name []type

使用make()方法定义切片

var slice_name []type = make([]type,len)
简写:
slice_name := make([]type,len)

指定容量
slice_name := make([]type,len,capacity)

len()和cap()方法

  • len() : 获取切片的长度
  • cap() : 获取切片的最大容量

切片截取

func main() {
   /* 创建切片 */
   numbers := []int{0,1,2,3,4,5,6,7,8}   

   /* 打印原始切片 */
   fmt.Println("numbers ==", numbers)

   /* 打印子切片从索引1(包含) 到索引4(不包含)*/
   fmt.Println("numbers[1:4] ==", numbers[1:4])

   /* 默认下限为 0*/
   fmt.Println("numbers[:3] ==", numbers[:3])

   /* 默认上限为 len(s)*/
   fmt.Println("numbers[4:] ==", numbers[4:])

   numbers1 := make([]int,0,5)

   /* 打印子切片从索引  0(包含) 到索引 2(不包含) */
   number2 := numbers[:2]

   /* 打印子切片从索引 2(包含) 到索引 5(不包含) */
   number3 := numbers[2:5]
}

append()和copy()方法

var numbers []int

/* 允许追加空切片 */
numbers = append(numbers, 0)

/* 向切片添加一个元素 */
numbers = append(numbers, 1)

/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)

/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)

/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)

Range

Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对的 key 值。

func main() {

   nums := []int{1, 2, 3, 4, 5}

   for index, value := range nums {
      fmt.Printf("index: %v ,value: %v\n", index, value)
   }
}

Map

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

定义map

// 定义map
var map1 = map[string]string{}

// 使用make方法定义
map2 := make(map[int]string)

添加元素

map1 [ "decp" ] = "this is map1"

删除元素

delete(map1, "decp")

例子

import "fmt"

func main() {
   // 定义map
   var map1 = map[string]string{}

   // 使用make方法定义
   map2 := make(map[int]string)

   // 赋值
   map1 [ "decp" ] = "this is map1"
   map2 [1] = "this is map2"

   // 检查key是否存在
   decp, ok := map1 [ "decp" ]
   if ok {
      fmt.Printf("decp:%s\n", decp)
   }

   // 使用delete方法删除map中的元素
   delete(map1, "decp")

   decp2, ok := map1 [ "decp" ]
   if ok {
      fmt.Printf("decp:%s\n", decp2)
   } else {
      fmt.Println("key不存在")
   }
}

接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

type Print interface {
   printName(name string)
}

func printName(name string) {
	fmt.Printf("name : %s", name)
}

func main() {
	printName("innerpeacez")
}

方法

简单的可以理解为针对结构体定义的func,方法中也可以使用指针,不使用指针是其实操作的是结构体的副本,元信息不会改变

操作基本类型结构体

type Age int32

func (age Age) initAge() int32 {
   if age == 0 {
      age = 10
      return int32(age)
   }
   return int32(age)
}

func main() {
   age := Age(0)
   initAge := age.initAge()
   fmt.Println(initAge)
}

操作指针类型结构体

type People struct {
   Name string
   Age  int32
}

func (people *People) printPeople() {
   fmt.Printf("name: %s\n", people.Name)
   fmt.Printf("age: %v\n", people.Age)
}

func (people *People) updatePeople() {
   people.Age = 18
   people.Name = "zhw"
}

func main() {
   people := People{"innerpeacez", 14}
   people.printPeople()
   people.updatePeople()
   people.printPeople()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值