GO学习记录

发布时间:2023年12月28日

一、Go语言的源文件的拓展是.go

? ? ? ? 开发环境和工具:GOLAND

个人版开发:

企业版开发:

二、Go语言结构

????????1、package main? 定义一个名为main的包名

????????2、import "fmt"? ? 添加fmt包

????????3、func main()? ? 是程序开始执行的函数

? ? ? ? 4、定义变量:var? a? int? =? 21? (和C不同,变量名放在了变量类型前面)

? ? ? ? 5、//单行注释? ? ?/*......*/多行注释

? 在goland编辑器中
    单行注释的快捷键是    Ctrl+/
    多行注释的快捷键是    Alt+Shift+/

? ? ? ? 6、fmt.Println(...)?可以将字符串输出到控制台,并在最后自动增加换行字符 \n

? ? ? ? 7、当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:

????????????????Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序

????????????????需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小

????????????????写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面

????????????????向对象语言中?的 protected )

????????注:

func main()  
{  // 错误,{ 不能在单独的行上
    fmt.Println("Hello, World!")
}

三、Go语言风格

? ? ? ? 1.程序一般由关键字、常量、变量、运算符、类型和函数组成

? ? ? ? 2.Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。

????????????声明变量的一般形式是使用 var 关键字:

? ? ? ? 3.常量是一个简单值的标识符,在程序运行时,不会被修改的量。

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

? ? ? ? ? ?例:显式类型定义:?const b string = "abc"? ? ?隐式类型定义:?const b = "abc"

? ? ? ?多重赋值const?a,?b,?c?=?1,?false,?"str"?//多重赋值

? ? ? ? ? ? ? ? ? ??多个相同类型的声明可以简写为:const c_name1, c_name2 = value1, value2

? ? ? ? 4.常量还可以用作枚举:

const (
    Unknown = 0
    Female = 1
    Male = 2
)
数字 0、1 和 2 分别代表未知性别、女性和男性。

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过

? ? ? ? 5.iota,特殊常量,可以认为是一个可以被编译器修改的常量。

????????????????iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行

????????????????常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

????????????????iota 可以被用作枚举值:

const (
    a = iota
    b = iota
    c = iota
)
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;
所以 a=0, b=1, c=2 可以简写为如下形式:

const (
    a = iota
    b
    c
)

实例

package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

? ? ? ? 6.Go的算数运算符? ? A=10,B=20

运算符描述实例
+相加A + B 输出结果 30
-相减A - B 输出结果 -10
*相乘A * B 输出结果 200
/相除B / A 输出结果 2
%求余B % A 输出结果 0
++自增A++ 输出结果 11
--自减A-- 输出结果 9

? ? ? ? 7.Go的关系运算符? ? A=10,B=20

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

? ? ? ? 8.Go的逻辑运算符

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

? ? ? ? 9.Go的位运算符

Go 语言支持的位运算符如下表所示。假定 A 为60,B 为13:

运算符描述实例
&按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。(A & B) 结果为 12, 二进制为 0000 1100
|按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或(A | B) 结果为 61, 二进制为 0011 1101
^按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。(A ^ B) 结果为 49, 二进制为 0011 0001
<<左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。A << 2 结果为 240 ,二进制为 1111 0000
>>右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。A >> 2 结果为 15 ,二进制为 0000 1111

? ? ? ? 10.Go的赋值运算符

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

11.Go的其它运算符

下表列出了Go语言的其他运算符。

运算符描述实例
&返回变量存储地址&a; 将给出变量的实际地址。
*指针变量。*a; 是一个指针变量

12.Go的运算符优先级

有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:

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

四、Go语言条件语句

1.if语句

(if 语句 由一个布尔表达式后紧跟一个或多个语句组成)

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
}

例子:
package main

import "fmt"

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

以上代码执行结果为:

a 小于 20
a 的值为 : 10

2.if..else语句

(if 语句后可以使用可选的else语句,else语句中的表达式在布尔表达式为 false 时执行)

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
} else {
  /* 在布尔表达式为 false 时执行 */
}

例子:
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

3.if嵌套语句

(可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句)

if 布尔表达式 1 {
   /* 在布尔表达式 1 为 true 时执行 */
   if 布尔表达式 2 {
      /* 在布尔表达式 2 为 true 时执行 */
   }
}

例子:
package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
 
   /* 判断条件 */
   if a == 100 {
       /* if 条件语句为 true 执行 */
       if b == 200 {
          /* if 条件语句为 true 执行 */
          fmt.Printf("a 的值为 100 , b 的值为 200\n" );
       }
   }
   fmt.Printf("a 值为 : %d\n", a );
   fmt.Printf("b 值为 : %d\n", b );
}

以上代码执行结果为:

a 的值为 100 , b 的值为 200
a 值为 : 100
b 值为 : 200

4.switch语句

( 用于基于不同条件执行不同动作)

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

实例:
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 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。

Type Switch 语法格式如下:

switch x.(type){
    case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定义任意个数的case */
    default: /* 可选 */
       statement(s);
}
实例
package main

import "fmt"

func main() {
   var x interface{}
     
   switch i := x.(type) {
      case nil:  
         fmt.Printf(" x 的类型 :%T",i)                
      case int:  
         fmt.Printf("x 是 int 型")                      
      case float64:
         fmt.Printf("x 是 float64 型")          
      case func(int) float64:
         fmt.Printf("x 是 func(int) 型")                      
      case bool, string:
         fmt.Printf("x 是 bool 或 string 型" )      
      default:
         fmt.Printf("未知型")    
   }  
}
以上代码执行结果为:

x 的类型 :<nil>

?????????使用 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")
    }
}
以上代码执行结果为:

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

? ? ? ? 总结从以上代码输出的结果可以看出:switch 从第一个判断表达式为 true 的 case 开始执行,如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。?

5.select语句

(select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行?)

select {
  case <- channel1:
    // 执行的代码
  case value := <- channel2:
    // 执行的代码
  case channel3 <- value:
    // 执行的代码

    // 你可以定义任意数量的 case

  default:
    // 所有通道都没有准备好,执行的代码
}

实例::::::
package main

import (
    "fmt"
    "time"
)

func main() {
    // 定义两个通道
    c1 := make(chan string)
    c2 := make(chan string)

    // 启动两个 goroutine(协程),分别从两个通道中获取数据
    go func() {
        time.Sleep(1 * time.Second)
        c1 <- "one"
    }()
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "two"
    }()
    
    // 使用 select 语句非阻塞地从两个通道中获取数据
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-c1:
            fmt.Println("received", msg1)
        case msg2 := <-c2:
            fmt.Println("received", msg2)
        //default:
             如果两个通道都没有可用的数据,则执行这里的语句
            //fmt.Println("no message received")
        }
    }
}


以上代码执行结果为:

received one
received two

五、Go语言循环语句

1. for循环语句 (重复执行语句块)

? ? ? ? for循环的三种形式:

①.和C一样

for init; condition; post { }

②.和C的while一样

for condition { }

③.和C的for(;;)一样

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

?六、Go语言函数

go语言的函数格式:

func function_name( [parameter list] ) [return_types] { 
    函数体 
}


/*
函数定义解析: 
func:函数由 func 开始声明 
function_name:函数名称,参数列表和返回值类型构成了函数签名。 
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。 return_types:返回类型,函数返回一列值。
return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 
return_types 不是必须的。 函数体:函数定义的代码集合。
*/


Go 函数可以返回多个值,例如:

实例:
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语言数组

1.基础知识:数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1

2.声明数组:

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

var variable_name [SIZE] variable_type

实例:var balance [10] float32

3.初始化数组:

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

1.如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

2.如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

//  将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}

注:初始化数组中?{}?中的元素个数不能大于?[]?中的数字/如果忽略?[]?中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小

八、Go语言指针

? ? ? ? 说明:一个指针变量指向了一个值的内存地址

声明格式如下:

var var_name *var-type

实例:这是一个指向 int 和 float32 的指针
var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

九、Go语言切片(简单来说就是动态数组,数组长度可变)

1.定义切片

????????①声明一个未指定大小的数组(切片不需要说明长度)

var identifier [ ]type

? ? ? ? ②使用make 函数来创建切片

var slices [?]type = make([ ] type,len)

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

????????③指容量,其中capacity为可数参数

make([ ]T,length,capacity)

2.切片初始化

①直接初始化切片,[ ]表示切片类型,初始化值依次为1,2,3,其中cap = len = 3

s := [ ]int {1,2,3}

②初始化切片s,是数组arr的引用

s := arr[ : ]?

?③将数组从下标索引startindex到endindex-1下的元素创建为一个新的切片

s := arr[ startIndex:endIndex ]

④默认endIndex时将表示一直到arr数组最后一个元素表示为一个切片

s := arr[startIndex :]

⑤默认startIndex时将表示从arr的第一个元素开始

s:= arr[ : endIndex]

⑥通过切片s初始化切片s1

s1 = s[startIndex : endIndex]

⑦通过内置函数make()初始化切片s,[]int标识为其元素类型类型为int的切片

s := make([ ]int,len,cap)?

十、结构体字段命名及使用范围

package main

import "fmt"

// 定义一个名为 Person 的结构体
type Person struct {
    Name string // 可导出的字段
    age  int    // 私有的字段
}

func main() {
    // 创建 Person 结构体的实例
    p := Person{
        Name: "Alice",
        age:  25,
    }

    fmt.Println(p.Name) // 可以访问可导出的字段
    // fmt.Println(p.age)  // 无法访问私有的字段,会编译错误
}

十一、goland的重构快捷键

十一、函数和接口的区别

  • 函数是一段可执行的代码块,用于实现特定的功能,而接口是一种抽象的类型,用于定义一组方法的集合。
  • 函数可以独立定义和调用,而接口需要被类型实现才能使用。
  • 函数可以接收参数和返回结果,而接口只定义方法的签名,不包含具体的实现。
  • 函数通常用于封装可重用的代码逻辑,而接口用于定义多个类型之间的共享行为。

可以使用以下生动的比喻来说明它们之间的区别:

想象一下你是一家快递公司的老板,而函数就像是你的员工,而接口则是你制定的一套操作规范。

  • 函数(function)就像是你的员工。每个函数都是一个独立的工作人员,他们各自有自己的任务和职责。你可以将特定的任务分配给不同的函数,并在需要时调用他们。每个函数相当于执行某项具体任务的工人。

  • 接口(interface)就像是你制定的操作规范。接口是一套定义了一组方法的规则,描述了工人应该具备的共同行为。你可以制定一份规范,例如所有的工人都必须具备“送货”和“签收”这两种行为。每个工人只要按照规范实现这两个方法,就可以成为符合规范的工人。

使用快递公司的例子,可以更容易理解函数和接口的区别。函数就像是具体的工人,而接口则是定义了工人应该有的共同行为的规范。这样,你可以根据具体的需求,雇佣不同的工人来完成不同的任务。而接口规范则确保了无论是哪位工人,他们都能完成规定的任务,从而保证了快递服务的质量和一致性。

文章来源:https://blog.csdn.net/tzxwoaini/article/details/131638151
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。