• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

go(01) 基础语法 - 物有本末,事有终始

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

go(01) 基础语法

索引 1. 数据类型 2.变量 3.结构体 4.运算符 5.条件 6.循环 7.函数 8.数组 9.指针 10.切片 11.Range(范围) 12.Map 13.递归 14.类型转换 15.接口 16.并发 17.错误及异常

go的语句结尾不需要分号(;)  遇到换行就代表一个语句的结束

1.数据类型 基本类型有:

  • bool
  • string
  • int、int8、int16、int32、int64
  • uint、uint8、uint16、uint32、uint64、uintptr
  • byte // uint8 的别名
  • rune // int32 的别名 代表一个 Unicode 码
  • float32、float64
  • complex64、complex128 

 

2.变量的声明和定义  var是声明变量的关键字

  变量声明的标准格式:   var 变量名 变量类型  变量声明以关键字 var 开头,后置变量类型,行尾无须分号

       批量格式: 

var ( a int
    b string
    c []int)

  简短格式: 名字 := 表达式  如:

func main() {
    x:=100
    a,s:=1, "abc"
}
需要注意的是,简短模式(short variable declaration)有以下限制:
    • 定义变量,同时显式初始化。
    • 不能提供数据类型。
    • 只能用在函数内部。

  因为简洁和灵活的特点,简短变量声明被广泛用于大部分的局部变量的声明和初始化。var 形式的声明语句往往是用于需要显式指定变量类型地方,或者因为变量稍后会被重新赋值而初始值无关紧要的地方。

  := 只能在函数里使用,在全局无法编译, 所以一般使用var的方式来定义全局变量

  注意:由于使用了 :=,而不是赋值的 =,因此推导声明写法的左值变量必须是没有定义过的变量。若定义过,将会发生编译错误。

     no new variables on left side of :=  在“:=”的左边没有新变量出现,意思就是“:=”的左边变量已经被声明了。

     但是 = 还是可以的,因为这是为变量赋值而非定义

多变量声明  vname1, vname2, vname3 = v1, v2, v3


  变量的初始化标准格式   var 变量名 类型 = 表达式 比如 var hp int = 100

  编辑器推到类型的格式  var hp = 100 在标准格式的基础上,将 int 省略后,编译器会尝试根据等号右边的表达式推导 hp 变量的类型。

 空标识符  如果一个字段在代码中从来不会被用到,那可以把它命名为 _,即空标识符

  它可以用来避免为某个变量起名 同时也可以在赋值时 舍弃某个值

  在函数中的 使用 

package main

import "fmt"

func main() {
  _,numb,strs := numbers() //只获取函数返回值的后两个
  fmt.Println(numb,strs)
}

//一个可以返回多个值的函数
func numbers()(int,int,string){
  a , b , c := 1 , 2 , "str"
  return a,b,c
}
输出结果:
2 str

 


  

3.结构体的定义  引自 : https://www.cnblogs.com/sparkdev/p/10761825.html

  结构体的定义格式如下

    type 类型名 struct {
        字段1 字段1的类型
        字段2 字段2的类型
         …
     }

  结构体中的字段可以是任何类型,甚至是结构体本身,也可以是函数或者接口。可以声明结构体类型的一个变量,然后像下面这样给它的字段赋值:

type Person struct {  定义结构体类型
    Name  string
    Age     int
    Email string
}
var p Person       声明结构体
p.Name = "nick"     给结构体的成员变量赋值
p.Age = 28

结构体的初始化及访问方法

package main

import "fmt"

type Person struct{
Name string
Age int
}

func main() {
person := Person {"李四",18}
fmt.Printf("%s , %d\n",person.Name , person.Age)
}

package main

import "fmt"

type Person struct{
    Name string
    Age     int
}

func main() {
    person := Person {"李四",18}
    printPerson(person)
}
func printPerson (person Person){
    fmt.Printf("%s , %d\n",person.Name , person.Age)
}
结构体作为函数形参
package main

import "fmt"

type Person struct{
    Name string
    Age     int
}

func main() {
    person := Person {"李四",18}
    printPerson(&person)
}
func printPerson (person *Person){
    fmt.Printf("%s , %d\n",person.Name , person.Age)
结构体指针

 


4.GO的运算符和C没什么分别

5.GO的条件语句 

package main

import "fmt"

func main() {
   /* 局部变量定义 */
   var a int = 100;
 
   /* 判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\n" );
   } else {
       /* 如果条件为 false 则执行以下语句 */
       fmt.Printf("a 不小于 20\n" );
   }
   fmt.Printf("a 的值为 : %d\n", a);

}
以上代码执行结果为:

a 不小于 20
a 的值为 : 100
if else语句

 

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var grade string = "B"
   var marks int = 90

   switch marks {
      case 90: grade = "A"
      case 80: grade = "B"
      case 50,60,70 : grade = "C"
      default: grade = "D"  
   }

   switch {
      case grade == "A" :
         fmt.Printf("优秀!\n" )    
      case grade == "B", grade == "C" :
         fmt.Printf("良好\n" )      
      case grade == "D" :
         fmt.Printf("及格\n" )      
      case grade == "F":
         fmt.Printf("不及格\n" )
      default:
         fmt.Printf("差\n" );
   }
   fmt.Printf("你的等级是 %s\n", grade );      
}
以上代码执行结果为:

优秀!
你的等级是 A
switch

 使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。

package main

import "fmt"

func main() {

    switch {
    case false:
            fmt.Println("1、case 条件语句为 false")
            fallthrough
    case true:
            fmt.Println("2、case 条件语句为 true")
            fallthrough
    case false:
            fmt.Println("3、case 条件语句为 false")
            fallthrough
    case true:
            fmt.Println("4、case 条件语句为 true")
    case false:
            fmt.Println("5、case 条件语句为 false")
            fallthrough
    default:
            fmt.Println("6、默认 case")
    }
}
以上代码执行结果为:

2case 条件语句为 true
3case 条件语句为 false
4case 条件语句为 true
fallthrough

  select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。

  select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。

以下描述了 select 语句的语法:

    • 每个 case 都必须是一个通信
    • 所有 channel 表达式都会被求值
    • 所有被发送的表达式都会被求值
    • 如果任意某个通信可以进行,它就执行,其他被忽略。
    • 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
      否则:
      1. 如果有 default 子句,则执行该语句。
      2. 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。
package main

import "fmt"

func main() {
   var c1, c2, c3 chan int
   var i1, i2 int
   select {
      case i1 = <-c1:
         fmt.Printf("received ", i1, " from c1\n")
      case c2 <- i2:
         fmt.Printf("sent ", i2, " to c2\n")
      case i3, ok := (<-c3):  // same as: i3, ok := <-c3
         if ok {
            fmt.Printf("received ", i3, " from c3\n")
         } else {
            fmt.Printf("c3 is closed\n")
         }
      default:
         fmt.Printf("no communication\n")
   }    
}
以上代码执行结果为:

no communication
select

 


 

6.GO的循环语句

  Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

  和 C 语言的 for 一样:

  for init; condition; post { }

  和 C 的 while 一样:

  for condition { }

  和 C 的 for(;;) 一样:

  for { }
  • init: 一般为赋值表达式,给控制变量赋初值;
  • condition: 关系表达式或逻辑表达式,循环控制条件;
  • post: 一般为赋值表达式,给控制变量增量或减量。

具体实例参考 :https://www.runoob.com/go/go-loops.html


 

7.GO函数

  func [函数名] (函数形参,...) 返回类型 { 函数体 }

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
   var ret int

   /* 调用函数并返回最大值 */
   ret = max(a, b)

   fmt.Printf( "最大值是 : %d\n", ret )
}

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 定义局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result
}
以上实例在 main() 函数中调用 max()函数,执行结果为:

最大值是 : 200
函数调用

 

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}
以上实例执行结果为:

Runoob Google
函数多个返回值

 

Go 语言可以很灵活的创建函数,并作为另外一个函数的实参。以下实例中我们在定义的函数中初始化一个变量,该函数仅仅是为了使用内置函数 math.sqrt(),实例为:

实例
package main

import (
   "fmt"
   "math"
)

func main(){
   /* 声明函数变量 */
   getSquareRoot := func(x float64) float64 {
      return math.Sqrt(x)
   }

   /* 使用函数 */
   fmt.Println(getSquareRoot(9))

}
以上代码执行结果为:

3
函数作为另一个函数的实参

 

   闭包的概念是 在函数A里创建 匿名函数B , 当A定义一个局部变量,一般情况下该变量会随着函数A的结束而释放, 但如果这时 B 调用了该变量, 函数A结束时该变量仍会存在于内存中, 当再次调用 A 时函数内部定义的局部变量 仍会是上一次调用的变量

  闭包的作用 , 可以让临时变量在外部函数生命周期结束时,仍然存在于内存之中!

  闭包的弊端 ,由于闭包会使函数中的变量保存在内存中,内存消耗很大,所以不能滥用闭包,解决办法是,退出函数之前,将不使用的局部变量删除。

package main

import "fmt"

func testfunc() func() int{
    i:=0
    return func() int{
        i+=1
        return i
    }
}


func main() {
    x := testfunc() //x是一个函数 因为:=的特殊 会根据右值来定义左值的类型
    fmt.Println(x())
    fmt.Println(x())
    fmt.Println(x())   
}
闭包

 


 

8.GO数组

  数组其实就是一个指向一块连续地址的指针

  声明数组 var variable_name [SIZE] variable_type

  初始化数组与访问的方法和C无异, 注意如果数组的value不是在声明时初始化, 那之后只能通过访问数组下标的方式赋值

package main

import "fmt"

func main() {
    var arr = [3]int {0,1,2}
    //也可 arr := [3]int {0,1,2}
    for i:=0;i<3;i++{
        fmt.Printf("%d \n", arr[i])
    }
}

  二维数组的定义及访问

package main

import "fmt"

func main() {
    var arr [3][4]int
    for i:= 0; i<3; i++{
        for j:=0; j<4; j++{
            arr[i][j] = j
        }
    }
    for i:= 0; i<3; i++{
        for j:=0; j<4; j++{
            fmt.Printf("%d\n",arr[i][j])
        }
    }
}
执行结果
0
1
2
3
0
1
2
3
0
1
2
3
View Code

  向函数传递数组


func func_name (praams []int ){ ... }  不指明数组长度

func func_name (praams [len]int ){ ... } 指明数组长度

var array = []int{1, 2, 3, 4, 5}
    /* 未定义长度的数组只能传给不限制数组长度的函数 */
setArray(array)
    /* 定义了长度的数组只能传给限制了相同数组长度的函数 */
var array2 = [5]int{1, 2, 3, 4, 5}

 


 

9.GO指针

  定义指针 var var_name *var-type

   指针使用和C的无异 

package main

import "fmt"

func main() {
    a := 10
    p:= &a
    fmt.Printf("指针指向的值%d\n指针本身的地址%x\n指针指向的地址%x\n",*p,p,&p)
}
运行结构

指针指向的值10
指针本身的地址c0000160a0
指针指向的地址c00000e028

  指针数组 var ptr [len]*int

package main

import "fmt"

const MAX int = 3

func main() {
   a := []int{10,100,200}
   var i int
   var ptr [MAX]*int;

   for  i = 0; i < MAX; i++ {
      ptr[i] = &a[i] /* 整数地址赋值给指针数组 */
   }

   for  i = 0; i < MAX; i++ {
      fmt.Printf("a[%d] = %d\n", i,*ptr[i] )
   }
}
以上代码执行输出结果为:

a[0] = 10
a[1] = 100
a[2] = 200
指针数组

  二级指针 var ptr1 *int a var ptr2 **int b  b = &a

package main

import "fmt"

func main() {

   var a int
   var ptr *int
   var pptr **int

   a = 3000

   /* 指针 ptr 地址 */
   ptr = &a

   /* 指向指针 ptr 地址 */
   pptr = &ptr

   /* 获取 pptr 的值 */
   fmt.Printf("变量 a = %d\n", a )
   fmt.Printf("指针变量 *ptr = %d\n", *ptr )
   fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
}
以上实例执行输出结果为:

变量 a = 3000
指针变量 *ptr = 3000
指向指针的指针变量 **pptr = 3000
二级指针

  指针作为函数的形参

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int= 200

   fmt.Printf("交换前 a 的值 : %d\n", a )
   fmt.Printf("交换前 b 的值 : %d\n", b )

   /* 调用函数用于交换值
   * &a 指向 a 变量的地址
   * &b 指向 b 变量的地址
   */
   swap(&a, &b);

   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}

func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保存 x 地址的值 */
   *x = *y      /* 将 y 赋值给 x */
   *y = temp    /* 将 temp 赋值给 y */
}
以上实例允许输出结果为:

交换前 a 的值 : 100
交换前 b 的值 : 200
交换后 a 的值 : 200
交换后 b 的值 : 100
swap
package main

import "fmt"

func main() {
    /* 定义局部变量 */
   var a int = 100
   var b int= 200
   swap(&a, &b);

   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}

/* 交换函数这样写更加简洁,也是 go 语言的特性,可以用下,c++ 和 c# 是不能这么干的 */
 
func swap(x *int, y *int){
    *x, *y = *y, *x
}
更简洁的swap

 


 10.GO 切片(slice)

   切片类似于动态数组, 长度可追加,

  定义切片有三种:

    1.声明一个未指定长度的数组  var identifier []type 

    2.通过内置函数make()创建切片 var slie_name [ ]type = make([ ]type , len , [cap])

          []type是数据类型 len是切片长度(长度不可大于容量否则报错) cap是切片容量(可选参数,如果不给则默认等于len)

    3.通过引用已经存在的数组创建  var arr = [6]int {0,1,2,3,4,5}

      slice := arr[start_index:end_index-1] 引用arr下标从start_index到end_index-1的的元素作为初始化切片的值

      slice := arr[1:3] slice未指定长度所以是切片 , 引用arr数组的下标1到下标3-1的两个元素来初始化新创建的切片

      s := arr[start_index:]  默认从start_index开始一直到数组的最后一个元素

      s := arr[:end_index-1]  默认从第一个元素开始一直到指定的下标为end_index-1结束

  如果创建切片时未初始化那么切片默认是空的, len=0 , cap=0 , slice=nil

  切片有两个内置函数 len(slice) 和cap(slice) , len获取切片的长度 , cap获取切片的容量

  append()和copy()

    如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)

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

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

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

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

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

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
以上代码执行输出结果为:

len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]
append和copy的方法

 


 11.GO Range

  Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。

  range关键字会返回两个值(索引和索引对应的值), 可以用 _(空标识符)来舍弃不需要的值

package main
import "fmt"
func main() {
    arr := []int {0,1,2,3,4}
    for n,v := range arr{
        fmt.Println("index:",n)
        fmt.Println("value:",v)
    }
}
执行结果

index: 0
value: 0
index: 1
value: 1
index: 2
value: 2
index: 3
value: 3
index: 4
value: 4


也可 用于map的遍历

package main

import "fmt"

func main() {
  kvs := map[int]string{1:"hello",2:"world",3:"!"}
  for k,v:= range kvs{
    fmt.Printf("[%d]%s\n",k,v)
  }
}

执行结果

[1]hello
[2]world
[3]!

 


 

12.GO Map

  声明map可以使用map关键字也可以使用内置函数make , 声明map默认是nil  

var map_name map[key_type]value_type 只声明默认是nil
map_name := make([key_type]value_type)
map插入key和value 
var map_name [int]string
map_name [1] = "hello"
map_name [2] = "world"
map_name [3] = "!"
定义map并初始化 type_map := map[int]string {1:"a",2:"b",3:"c"}

  delete() 用于删除集合元素

  delete(map_name,map_key) 删除指定map里的指定索引值代表的value

 


 

13.GO递归函数

  递归函


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Go-01 安装 Go开发的工具发布时间:2022-07-10
下一篇:
Go语言常用命令发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap