一、Go基础知识入门

news2025/2/22 20:15:27

1、go语言介绍

 

2、go开发环境搭建

2.1、go的安装

  • go下载地址:All releases - The Go Programming Language,windows选择下载go1.20.2.windows-amd64.msi文件。

  • 双击go1.20.2.windows-amd64.msi,点击"Next",然后勾选同意,再点击"Next"。

  • 选择Go的安装位置,这里我选择了"D:\0-software\0-develop\10-GO\1-go1.20.2"。再点击"Next"。

  • 点击"Install"进行安装。然后点击"Finish"就安装完成了。

 

2.2、go的环境变量配置 

  • 此电脑->右键"属性"->"高级系统设置"->"环境变量"

  • 在系统变量里面添加:

  • 变量名:GOPATH

    变量值:D:\0-software\0-develop\10-GO\1-go1.20.2

  • 在Path里面添加:%GOPATH%\bin

  • 然后打开cmd,输入"go version",打印下图所示,说明环境变量配置成功。

goLand的安装、配置

  • goLand下载地址:GoLand by JetBrains: More than just a Go IDE,安装过程省略。

  • 新建go工程时,选择Go,不要选择Go(GOPATH),早期的GoLand比如2020版本的才选择Go(GOPATH)。

2.3、go开发之hello-world

  • 点击"File"->"new"->"Go File",编辑文件名为"Hello"

     

  • 可以看到默认会有一个package包名。每一个go的源码文件都要指定包名。并且只有package是main的代码才会运行。

  • func表示函数的意思。

  • 注意:Go语言的Hello World你想要运行的话要注意:

    1. 包名必须叫main

    2. 函数名也必须叫main

    3. 同一个目录下只能有一个func main()

  • 点击绿色的三角按钮执行。

  • 还可以通过另外一种方式运行:

    1. 进入到Hello.go所在目录文件夹

    2. 然后执行go build .\Hello.go,这样可以将Hello.go编译成可执行文件。

    3. 然后执行:.\Hello.exe,就可以执行了。

    4. 如果想省略编译过程直接执行,可以输入:

      go run .\Hello.go
      

      这样就不会编译生成Hello.exe文件,而且还会执行。

3、变量和常量

3.1、如何定义变量

package main

import "fmt"

// 全局变量和局部变量(定义在main外面的变量都是全局变量)
//var sex = "male"
//var ok bool = true

// 简洁方式定义全局变量
var (
	sex = "male"
	ok  = true
	age = 18
)

//局部变量定义了就必须使用,不使用会报错;全局变量定义了之后可以不使用,不会报错。

func main() {
	//go是静态语言,静态语言和动态语言相比,定义变量差异很大
	//1、变量必须想定义后使用 2、变量必须有类型 3、变量类型定下来之后不能改变
	//定义变量的方式
	//方式一:var variableName variableType
	var name string
	name = "旺财"
	//演示:变量类型定下来之后不能改变
	//name = 1

	fmt.Print(name)

	/*
		方式二:var variableName = variableValue
		可以省略variableType,因为go可以通过variableValue进行类型推断。
	*/

	var name2 = "小强"
	fmt.Print(name2)

	/*
		方式三:variableName := variableValue
		这种平时用的比较多
	*/

	//var age = 1
	age := 1
	fmt.Print(age)

	//go语言中局部变量定义了但是不使用,是不行的。

	//2、多变量定义
	//2、多变量定义
	//2.1、同时在一行里面定义3个string类型的变量
	var user1, user2, user3 string
	fmt.Print(user1, user2, user3)
	//2.2、同时在一行里面定义3个变量,并且初始化。
	var user4, user5, user6 = "小强", "旺财", 1
	fmt.Print(user4, user5, user6)

	/*
		注意:
			变量必须先定义再使用
			go语言是静态语言,要求变量的类型和肤质类型一致
			局部变量名不能冲突;全局变量和局部变量的变量名可以重复,这种情况下,局部变量的优先级高。
			简洁变量定义不能用于全局变量(方式三:variableName := variableValue)
			变量是有零值的
			局部变量定义了就必须使用,不使用会报错;全局变量定义了之后可以不使用,不会报错。
	*/

}

3.2、常量的定义和使用

package main

import "fmt"

func main() {
	//常量,定义的时候就指定的值,不能修改。
	//常量定义的时候全部大写。多个单词中间加下划线。
	const PI1 float32 = 3.1415926535897932384626 //显式定义
	const PI2 = 3.1415926535897932384626         //隐式定义

    // 同时定义多个常量
	const (
		UNKNOWN = 1
		FEMALE  = 2
		MALE    = 3
	)

    // 同时定义多个常量,并且支持类型定义。
	const (
		X int = 1
		Y
		S = "abc"
		Z
		M
	)
	fmt.Println(X, Y, S, Z, M)

	/*
		1、常量类型只可以定义bool、数值(整数、浮点数和复数) 和 字符串;
		2、不曾使用的常量,没有强制使用的要求;
		3、显式指定类型的时候,必须确保常量 左右值类型一致。
		4、常量在定义的时候如果没有设置类型和值的话,它就用前面的类型和值。
	*/

}

代码执行结果:

         从打印结果可以看出,Y没有定义类型和值,但是Y可以使用前面X的类型和值。M也是同样的道理。

3.3、iota的使用细节

package main

import "fmt"

func main() {
	//iota,特殊常量,可以认为是一个可以被编译器修改的常量。
	const (
		ERR1 = iota + 1
		ERR2
		ERR3
		ERR4 = "abc"
		ERR5
		ERR6 = 100
		ERR7 = iota
	)

	const (
		ERRNEW1 = iota
	)

	fmt.Println(ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7)
	fmt.Println(ERRNEW1)
	/*
		如果中断了iota那么必须显式的恢复,后续会自动递增。
		自增类型默认是int类型
		iota能简化const类型的定义
		每次出现const的时候,iota初始化为0
	*/

}
代码运行结果:

​

3.4、匿名变量的定义和用途

package main

func a() (int, bool) {
	return 0, false
}

func main() {
	//匿名变量:就是一个下划线
	var _ int
	//r1, ok := a()
	_, ok := a()
	/*
		如果我接下来只想使用ok,不想使用r1,根据Go的局部变量定义规定的,定义了就必须使用,那我就必须在下面被迫的加一个多余的打印r1的代码。
		有什么好办法吗?
		这时,匿名变量就登场了。可以使用"_"代替r1,这样在下面可以不用也不会报错了。
	*/
	if ok {
		//打印
		
	}
}

3.5、变量的作用域

package main

import "fmt"

// 全局变量:任何一个函数都可以使用这个变量
var globalVariable = "旺财"

func main() {
	//变量的作用域

	//局部变量
	localVariable := "小强"
	fmt.Print(localVariable)

	{
		//局部变量
		localVariable2 := "张三"
		fmt.Print(localVariable2)
	}
	//在局部变量作用域外部打印该变量会报错
	//fmt.Print(localVariable2)

}

4、go的基础数据类型

4.1、数值、浮点数和字符类型

package main

import "fmt"

func main() {
	//基础数据类型
	//var a int8
	//var b int16
	//var c int32
	//var d int64
	//var ua uint8
	//var ub uint16
	//var uc uint32
	//var ud uint64
	动态类型,用的时候就会知道,用起来挺麻烦的
	//var e int
	//
	类型转换需要强转才行
	//a = int8(b)
	//
	//var f1 float32
	//var f2 float64
	//
	//f1 = 3
	//f2 = 3.14

	//主要是用来存放英文字符的
	var c byte
	c = 'a' + 1
	fmt.Println(c)        //值是98
	fmt.Printf("c=%c", c) //打印的是 c=b

	c1 := 97
	fmt.Println()
	fmt.Printf("c1=%c", c1) //打印的是 c=a

	//也是字符,主要是用来存放中文字符的
	var c2 rune
	c2 = '旺'
	fmt.Println()
	fmt.Printf("c=%c", c2) //打印的是 c=旺

	//字符串
	var name string
	name = "My name is Peter Parker,I am a Super Hero. I don't like the Criminals."
	fmt.Println()
	fmt.Println(name)
}
运行结果:

bool类型

        布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true

数值型

  1. 整数型

可以简单讲解一下二进制和位数的关系,以及int和uint的关系

  • int8 有符号 8 位整型 (-128 到 127) 长度:8bit

  • int16 有符号 16 位整型 (-32768 到 32767)

  • int32 有符号 32 位整型 (-2147483648 到 2147483647)

  • int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)

  • uint8 无符号 8 位整型 (0 到 255) 8位都用于表示数值:

  • uint16 无符号 16 位整型 (0 到 65535)

  • uint32 无符号 32 位整型 (0 到 4294967295)

  • uint64 无符号 64 位整型 (0 到 18446744073709551615)

  1. 浮点型

  • float32 32位浮点型数

  • float64 64位浮点型数

其他

  • byte 等于 uint8

  • rune 等于 int32

  • uint 32 或 64 位

字符

        Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。 ​ 字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。也就是说对于传统的字符串是由字符组成的,而Go的字符串不同,它是由字节组成的。

package main

import (
	"fmt"
)

func main() {

	var a byte
	a = 'a'
	//输出ascii对应码值 。。 这里说明一下什么是ascii码
	fmt.Println(a)
	fmt.Printf("a=%c", a)
}

        字符常量只能使用单引号括起来,例如:var a byte = ‘a’ var a int = ‘a’

package main

import (
	"fmt"
)

func main() {

	var a byte
	a = "a"
	//输出ascii对应码值 。。 这里说明一下什么是ascii码
	fmt.Println(a)
	fmt.Printf("a=%c", a)
}

        字符本质是一个数字, 可以进行加减乘除

package main

import (
	"fmt"
	"reflect"
)

func main() {

	a := 'a'

	//这里注意一下 1. a+1可以和数字计算 2.a+1的类型是32 3. int类型可以直接变成字符

	fmt.Println(reflect.TypeOf(a+1))
	fmt.Printf("a+1=%c", a+1)
}

字符串

        字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。

4.2、基本类型的转换

package main

import (
	"fmt"
	"strconv"
)

func main() {
	//基本类型转换
	//int和int相互转换
	var a int8 = 12
	//var b = uint8(a)
	//fmt.Print(b)

	//float转int
	//var f float32 = 3.14
	//var c = int32(f)
	//fmt.Println(c) //打印的是3

	//int转float
	//var f64 = float64(a)
	//fmt.Println(f64) //打印的是12

	//定义别名
	type IT int //类型要求很严格
	var c = IT(a)
	fmt.Println(c)

	//字符串转数字
	var istr = "12"
	myint, err := strconv.Atoi(istr)
	if err != nil {
		fmt.Println("convert erro")
	}
	fmt.Println(myint)

	//数字转字符串
	var myi = 32
	fmt.Println(strconv.Itoa(myi))
	
}

type 关键字:

        在 Go 语言中,type 关键字常被我们用来创建新的结构体。同样的,type 也可以用来创建其它的用户自定义类型。在创建新类型时,有类型别名和类型定义两种方式,你知道它们的区别吗?

1、type 关键字

        对于使用过 Go 语言的人,相信对type关键字都不陌生,它可以帮助我们定义结构体或接口:

type Student struct{

}

type Man interface {
    Name()
}

        在使用 type 定义结构体时,我们可以把它看作是基于struct{}类型定义了一个新的类型Student

        其实,除了用于创建新类型,type还有创建类型别名的作用。

2、类型别名 vs 类型定义

基于一个类型创建一个别名,称之为类型别名 (alias)。

基于一个类型创建一个新类型,称之为类型定义 (definition)。

type Int1 = int // 类型别名,Int1 是 int 类型的别名
type Int2 int // 类型定义,Int2 是新类型

它们之间的区别是什么呢?

        以上述定义的Int1Int2为例,我们可以用int类型的变量初始化Int1类型,因为Int1只是int类型的一个别名。

        但如果我们用一个int类型的变量初始化Int2类型时,对Int2类型的初始化会报错,因为Int2是一个新的类型。

type Int1 = int // 类型别名,Int1 是 int 类型的别名
type Int2 int // 类型定义,Int2 是新类型

var i int = 0

var i1 Int1 = i
var i2 Int2 = i // error

        不过,Int1类型和Int2类型都可以用相应类型的字面量来初始化。

type Int1 = int // 类型别名,Int1 是 int 类型的别名
type Int2 int // 类型定义,Int2 是新类型

var i1 Int1 = 0
var i2 Int2 = 0

4.2.1、简单的转换操作

valueOfTypeB = typeB(valueOfTypeA)
代码块1
// 浮点数
a := 5.0

// 转换为int类型
b := int(a)

//Go允许在底层结构相同的两个类型之间互转。例如:
// IT类型的底层是int类型
type IT int

// a的类型为IT,底层是int
var a IT = 5

// 将a(IT)转换为int,b现在是int类型
b := int(5)

// 将b(int)转换为IT,c现在是IT类型
c := IT(b)

var a int32 = 1
var b int64 = 3
b = int64(a)
fmt.Println(a, b)

/*
    不是所有数据类型都能转换的,例如字母格式的string类型"abcd"转换为int肯定会失败
    低精度转换为高精度时是安全的,高精度的值转换为低精度时会丢失精度。例如int32转换为int16,float32转换为int
    这种简单的转换方式不能对int(float)和string进行互转,要跨大类型转换,可以使用strconv包提供的函数
*/
 

4.2.2、strconv

Itoa和Atoi

int转换为字符串:Itoa()

println("a" + strconv.Itoa(32))  // a32

string转换为int:Atoi()(表示 alphanumeric to integer)是把字符串转换成整型数的一个函数

i,_ := strconv.Atoi("3")
println(3 + i)   // 6

// Atoi()转换失败
i,err := strconv.Atoi("a")
if err != nil {
    println("converted failed")
}
//由于string可能无法转换为int,所以这个函数有两个返回值:第一个返回值是转换成int的值,第二个返回值判断是否转换成功。

4.3、format进行格式化转换

Parse类函数

        Parse类函数用于转换字符串为给定类型的值:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。

b, err := strconv.ParseBool("true")
f, err := strconv.ParseFloat("3.1415", 64)
i, err := strconv.ParseInt("-42", 10, 64)
u, err := strconv.ParseUint("42", 10, 64)

ParseInt()和ParseUint()有3个参数:

func ParseInt(s string, base int, bitSize int) (i int64, err error)
func ParseUint(s string, base int, bitSize int) (uint64, error)

说明:

  1. bitSize参数表示转换为什么位的int/uint,有效值为0、8、16、32、64。当bitSize=0的时候,表示转换为int或uint类型。例如bitSize=8表示转换后的值的类型为int8或uint8。

  2. base参数表示以什么进制的方式去解析给定的字符串,有效值为0、2-36。当base=0的时候,表示根据string的前缀来判断以什么进制去解析:0x开头的以16进制的方式去解析,0开头的以8进制方式去解析,其它的以10进制方式解析。

Format类函数

        将给定类型格式化为string类型:FormatBool()、FormatFloat()、FormatInt()、FormatUint()。

s := strconv.FormatBool(true)
s := strconv.FormatFloat(3.1415, 'E', -1, 64)
s := strconv.FormatInt(-42, 16) //表示将-42转换为16进制数,转换的结果为-2a。
s := strconv.FormatUint(42, 16)

        第二个参数base指定将第一个参数转换为多少进制,有效值为2<=base<=36。当指定的进制位大于10的时候,超出10的数值以a-z字母表示。例如16进制时,10-15的数字分别使用a-f表示,17进制时,10-16的数值分别使用a-g表示。

FormatFloat()参数众多:

func FormatFloat(f float64, fmt byte, prec, bitSize int) string

        bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。 ​

        fmt表示格式:‘f’(-ddd.dddd)、‘b’(-ddddp±ddd,指数为二进制)、‘e’(-d.dddde±dd,十进制指数)、‘E’(-d.ddddE±dd,十进制指数)、‘g’(指数很大时用’e’格式,否则’f’格式)、‘G’(指数很大时用’E’格式,否则’f’格式)。 ​

        prec控制精度(排除指数部分):对’f’、‘e’、‘E’,它表示小数点后的数字个数;对’g’、‘G’,它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。

4.4、运算符和表达式

4.4.1、算数运算符

      • / %(求余) ++ –

4.4.2、关系运算符

== != > < >= <=

4.4.3、逻辑运算符

&&所谓逻辑与运算符。如果两个操作数都非零,则条件变为真
||所谓的逻辑或操作。如果任何两个操作数是非零,则条件变为真
!所谓逻辑非运算符。使用反转操作数的逻辑状态。如果条件为真,那么逻辑非操后结果为假

这个和python不一样,python中使用 and or来连接

package main
​
import "fmt"
​
func main() {
   var a bool = true
   var b bool = false
   if ( a && b ) {
      fmt.Printf("第一行 - 条件为 true\n" )
   }
   if ( a || b ) {
      fmt.Printf("第二行 - 条件为 true\n" )
   }
   /* 修改 a 和 b 的值 */
   a = false
   b = true
   if ( a && b ) {
      fmt.Printf("第三行 - 条件为 true\n" )
   } else {
      fmt.Printf("第三行 - 条件为 false\n" )
   }
   if ( !(a && b) ) {
      fmt.Printf("第四行 - 条件为 true\n" )
   }
}

4.4.4、位运算符

位运算符对整数在内存中的二进制位进行操作。 ​ 下表列出了位运算符 &, |, 和 ^ 的计算:

PQP & QP | QP ^ Q
00000
01011
11110
10011

假定 A = 60; B = 13; 其二进制数转换为: A = 0011 1100 B = 0000 1101

A&B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001 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
package main

import "fmt"

func main() {

   var a uint = 60      /* 60 = 0011 1100 */  
   var b uint = 13      /* 13 = 0000 1101 */
   var c uint = 0          

   c = a & b       /* 12 = 0000 1100 */
   fmt.Printf("第一行 - c 的值为 %d\n", c )

   c = a | b       /* 61 = 0011 1101 */
   fmt.Printf("第二行 - c 的值为 %d\n", c )

   c = a ^ b       /* 49 = 0011 0001 */
   fmt.Printf("第三行 - c 的值为 %d\n", c )

   c = a << 2     /* 240 = 1111 0000 */
   fmt.Printf("第四行 - c 的值为 %d\n", c )

   c = a >> 2     /* 15 = 0000 1111 */
   fmt.Printf("第五行 - c 的值为 %d\n", c )
}

4.4.5、赋值运算符

下表列出了所有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
package main

import "fmt"

func main() {
   var a int = 21
   var c int

   c =  a
   fmt.Printf("第 1 行 - =  运算符实例,c 值为 = %d\n", c )

   c +=  a
   fmt.Printf("第 2 行 - += 运算符实例,c 值为 = %d\n", c )

   c -=  a
   fmt.Printf("第 3 行 - -= 运算符实例,c 值为 = %d\n", c )

   c *=  a
   fmt.Printf("第 4 行 - *= 运算符实例,c 值为 = %d\n", c )

   c /=  a
   fmt.Printf("第 5 行 - /= 运算符实例,c 值为 = %d\n", c )

   c  = 200;

   c <<=  2
   fmt.Printf("第 6行  - <<= 运算符实例,c 值为 = %d\n", c )

   c >>=  2
   fmt.Printf("第 7 行 - >>= 运算符实例,c 值为 = %d\n", c )

   c &=  2
   fmt.Printf("第 8 行 - &= 运算符实例,c 值为 = %d\n", c )

   c ^=  2
   fmt.Printf("第 9 行 - ^= 运算符实例,c 值为 = %d\n", c )

   c |=  2
   fmt.Printf("第 10 行 - |= 运算符实例,c 值为 = %d\n", c )

}

4.4.6、其他运算符

此处讲解一下什么是地址

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

import "fmt"

func main() {
   var a int = 4
   var b int32
   var c float32
   var ptr *int

   /* 运算符实例 */
   fmt.Printf("第 1 行 - a 变量类型为 = %T\n", a );
   fmt.Printf("第 2 行 - b 变量类型为 = %T\n", b );
   fmt.Printf("第 3 行 - c 变量类型为 = %T\n", c );

   /*  & 和 * 运算符实例 */
   ptr = &a     /* 'ptr' 包含了 'a' 变量的地址 */
   fmt.Printf("a 的值为  %d\n", a);
   fmt.Printf("*ptr 为 %d\n", *ptr);
}

4.4.7、运算符优先级

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

优先级分类运算符结合性
1逗号运算符,从左到右
2赋值运算符=、+=、-=、*=、/=、 %=、 >=、 <<=、&=、^=、|=从右到左
3逻辑或||从左到右
4逻辑与&&从左到右
5按位或|从左到右
6按位异或^从左到右
7按位与&从左到右
8相等/不等==、!=从左到右
9关系运算符<、<=、>、>=从左到右
10位移运算符<<、>>从左到右
11加法/减法+、-从左到右
12乘法/除法/取余*(乘号)、/、%从左到右
13单目运算符!、*(指针)、& 、++、–、+(正号)、-(负号)从右到左
14后缀运算符( )、[ ]、->从左到右

当然,你可以通过使用括号来临时提升某个表达式的整体运算优先级。

package main

import "fmt"

func main() {
   var a int = 20
   var b int = 10
   var c int = 15
   var d int = 5
   var e int;

   e = (a + b) * c / d;      // ( 30 * 15 ) / 5
   fmt.Printf("(a + b) * c / d 的值为 : %d\n",  e );

   e = ((a + b) * c) / d;    // (30 * 15 ) / 5
   fmt.Printf("((a + b) * c) / d 的值为  : %d\n" ,  e );

   e = (a + b) * (c / d);   // (30) * (15/5)
   fmt.Printf("(a + b) * (c / d) 的值为  : %d\n",  e );

   e = a + (b * c) / d;     //  20 + (150/5)
   fmt.Printf("a + (b * c) / d 的值为  : %d\n" ,  e );  
}

5、字符串基本操作

5.1、rune和字符串长度

package main

import "fmt"

func main() {
	//5.1节 rune和字符串长度
	//长度计算
	name := "lvxiaosha学go"
	fmt.Println(len(name))

	//将字符串类型的name转换为切片,然后就可以for循环了。
	bytes := []byte(name)
	fmt.Println(len(bytes))
	//因为 len() 传入 返回字符串所占的字节 ,而中文转 utf8 编码后占 3 字节,英文占 1 字节。所以上面两个输出结果都是:9 + 3 + 2 = 14

	//如果我们想得到字符长度,而不是字节长度,就需要转为 切片 后再计算长度。
	runes := []rune(name)
	fmt.Println(len(runes)) // 10
	
}

运行结果:

5.2、转义符

package main

import "fmt"

func main() {
	//5.2节转义符
	//想在字符串中打印双引号
	//方法1:使用反斜线加双引号(\")
	name := "\"吕小傻\""
	fmt.Println(name)

	//方法2:使用Tab键上面的那个键(`),注意不是单引号(')。
	//这个和python中的三引号("""xxx""")里面可以随便写内容类似。
	//我们大多数使用的都是这个方法。
	name2 := `"吕小傻"`
	fmt.Println(name2)
}

转义符

转义字符意义ASCII码值(十进制)
\n换行(LF) ,将当前位置移到下一行开头010
\r回车(CR) ,将当前位置移到本行开头013
\t水平制表(HT) (跳到下一个TAB位置)009
\\代表一个反斜线字符’’\’092
\’代表一个单引号(撇号)字符039
\"代表一个双引号字符034
\?代表一个问号063

5.3、格式化输出

package main

import (
	"fmt"
	"strconv"
)

func main() {
	//5.3节格式化输出
	userName := "吕小傻"
	address := "山东省青岛市"
	age := 18
	mobile := "13624558575"

	fmt.Println("用户名:"+userName, "地址:"+address, "年龄:"+strconv.Itoa(age), "电话:"+mobile) //这种拼接方式极难维护
	fmt.Printf("用户名:%s,地址:%s,年龄:%d,电话:%s\r\n", userName, address, age, mobile)         //这种方式更常用,但是性能没有上一种好。

	userMessage := fmt.Sprintf("用户名:%s,地址:%s,年龄:%d,电话:%s", userName, address, age, mobile)
	fmt.Println(userMessage)

	var ages []int = []int{1, 2, 3}
	agesMessage := fmt.Sprintf("年龄:%#v", ages)
	fmt.Println(agesMessage)
}

缺省格式和类型

格式化后的效果动词描述
[0 1]%v缺省格式
[]int64{0, 1}%#vgo语法打印
[]int64%T类型打印

整型(缩进, 进制类型, 正负符号)

格式化后的效果动词描述
15%d十进制
+15%+d必须显示正负符号
␣␣15%4dPad空格(宽度为4,右对齐)
15␣␣%-4dPad空格 (宽度为4,左对齐)
1111%b二进制
17%o八进制
f%x16进制,小写

字符(有引号, Unicode)

Value: 65   (Unicode letter A)

格式化后的效果动词描述
A%c字符
‘A’%q有引号的字符
U+0041%UUnicode
U+0041 ‘A’%#UUnicode 有引号

浮点(缩进, 精度, 科学计数)

Value: 123.456

格式化后的效果动词描述
1.234560e+02%e科学计数
123.456000%f十进制小数

字符串or 字节slice (引号, 缩进, 16进制)

Value: "cafe"

格式化后的效果动词描述
cafe%s字符串原样输出
␣␣cafe%6s宽度为6,右对齐

5.4、高性能字符串拼接-string.builder

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	//5.4节 高性能字符串拼接-string.builder
	userName := "吕小傻"
	address := "山东省青岛市"
	age := 18
	mobile := "13624558575"

	var builder strings.Builder
	builder.WriteString("用户名:")
	builder.WriteString(userName)
	builder.WriteString(",地址:")
	builder.WriteString(address)
	builder.WriteString(",年龄:")
	builder.WriteString(strconv.Itoa(age))
	builder.WriteString(",电话:")
	builder.WriteString(mobile)

	response := builder.String()
	fmt.Println(response)
}

运行结果:

 5.5、字符串的比较

package main

import "fmt"

func main() {
	//5.5节 字符串的比较
	a := "hello"
	b := "hello"
	fmt.Println(a == b)
	fmt.Println(a != b)

	//字符串的大小比较
	fmt.Println(a > b)

}

5.6、字符串操作常用方法

package main

import (
	"fmt"
	"strings"
)

func main() {
	//5.6节 字符串操作常用方法
	//strings常用方法
	//是否包含
	name := "My name is Peter Parker,I am a Super Hero.I don't like the Criminals."
	fmt.Println(strings.Contains(name, "Peter Parker"))

	//字符串长度
	runes := []rune(name)
	fmt.Println(len(runes))

	//查询字符串出现的次数
	fmt.Println(strings.Count(name, "a"))

	//分割字符串
	fmt.Println(strings.Split(name, ","))

	//字符串是否包含前缀,是否包含后缀。
	fmt.Println(strings.HasPrefix(name, "My"))
	fmt.Println(strings.HasSuffix(name, "Criminals."))

	//查询子串出现的位置
	fmt.Println(strings.Index(name, "Peter Parker"))
	fmt.Println(strings.IndexRune(name, []rune(name)[17]))

	//字符串替换
	fmt.Println(strings.Replace(name, "Peter Parker", "Super Man", 1)) // 1表示只替换第一个
	fmt.Println(strings.Replace(name, "Peter Parker", "Iron Man", -1)) // -1表示全部替换

	//大小写转换
	fmt.Println(strings.ToLower("Peter Parker"))
	fmt.Println(strings.ToUpper("Peter Parker"))

	//去掉字符串左右两边的特殊字符,下面的方法表示,只要字符串两边出现了"#"或"$",就去掉。
	//除了strings.Trim,还有strings.TrimLeft和strings.TrimRight方法
	fmt.Println(strings.Trim("$#Peter #Parker#", "#$"))

}

运行结果:

6.1、if条件判断

package main

import "fmt"

/*
*

	if 布尔表达式 {
	  逻辑
	}
*/
func main() {
	//6.1节 if条件判断
	age := 18
	country := "中国"
	//简单的if条件判断,布尔表达式的括号省略
	if age < 18 {
		fmt.Println("未成年")
	}

	//复杂的if条件判断,布尔表达式的括号不能省略
	if (age < 18) && (country == "中国") {
		fmt.Println("未成年")
	} else if age == 18 {
		fmt.Println("刚刚成年")
	} else {
		fmt.Println("成年了")
	}

}

6.2、for循环基础用法

package main

import (
	"fmt"
)

/*
 * go语言中只有for循环,没有while循环。
 * for init; condition; post {
 *   //do something
 *	}
 */
func main() {
	//6.1节 for循环基础用法
	//标准写法
	for i := 0; i < 3; i++ {
		fmt.Println(i)
	}

	//初始变量在循环外面定义
	var j int
	for ; j < 3; j++ {
		fmt.Println(j)
	}

	// init; condition; post 都没有,就等效与while(true)
	//var k int
	//for {
	//	//睡眠2秒
	//	time.Sleep(2 * time.Second)
	//	fmt.Println(k)
	//	k++
	//}

	// 可以将post部分放到循环体里面
	var m int
	for m < 3 {
		fmt.Println(m)
		m++
	}

}

6.3、for循环打印九九乘法表

package main

import "fmt"

/*
 * 6.3节 for循环打印九九乘法表
 * for循环打印九九乘法表
 */
func main() {
	//遍历,处理第几行
	for y := 1; y <= 9; y++ {
		//遍历,处理第几列。
		for x := 1; x <= y; x++ {
			fmt.Printf("%d * %d = %d\t", x, y, x*y)
		}
		fmt.Println()
	}

}

运行结果:

6.4、for range的循环用法

package main

import (
	"fmt"
)

/*
 * 6.4节 for range的循环用法,主要用于 字符串、数组、切片、map、channel
 */
func main() {
	name := "My name is Peter Parker."
	//for index, value := range name {
	//	fmt.Printf("%d, %c\r\n", index, value)
	//}

	for _, value := range name {
		fmt.Printf("%c\r\n", value)
	}

	/*
	 * 字符串  字符串的索引(key)  字符串对应的索引的字符值的拷贝(index),因为是字符串值的拷贝,所以在字符串循环时是改不了原字符串的  如果不写key,那么index返回的是索引
	 * for index := range name {
	 *     fmt.Printf("%c\r\n", index)
	 * }
	 *
	 * 数组  数组的索引          索引的对应值的拷贝                   如果不写key,那么value返回的是索引
	 * 切片  切片的索引          索引的对应值的拷贝                   如果不写key,那么value返回的是索引
	 * map  字符串的索引(key)    value 返回的是 key 对应值的拷贝      如果不写key,那么value返回的是map的值
	 * channel                value 返回的是 channel 接受的数据
	 */

	//下面这种方式循环字符串时会出现中文乱码
	name2 := "哈哈哈"
	for index := range name2 {
		fmt.Printf("%c\r\n", name2[index])
	}

	//下面这种方式循环字符串时,就不会出现中文乱码
	name3 := "哈哈哈"
	for _, value := range name3 {
		fmt.Printf("%c\r\n", value)
	}

}

6.5、for循环的continue和break语句

package main

import (
	"fmt"
	"time"
)

func main() {
	index := 0
	for {
		time.Sleep(1 * time.Second)
		index++

		//如果index等于5,就直接进入下一次循环,不执行下面的代码。
		if index == 5 {
			continue
		}

		fmt.Println(index)
		if index > 10 {
			//退出循环
			break
		}
	}
}

6.6、goto语句的基本用法

package main

import "fmt"

/*
 * 6.6节 goto语句的基本用法
 * goto语句可以让我们的代码跳到指定的代码块中运行,灵活性很强。但是开发中不建议使用。
 *
 * goto语句可以实现程序的跳转,goto语句使用场景最多的是程序的错误处理,也就是说当程序出现错误的时候统一跳转到相应的标签处,统一处理。
 */
func main() {
	for i := 0; i < 5; i++ {
		for j := 0; j < 5; j++ {
			if j == 2 {
				goto over
			}
			fmt.Println(i, j)
		}

	}

over:
	fmt.Println("over")

}

运行结果:

6.7、switch语法

package main

import "fmt"

/*
 * 6.7节 switch语句 比if语句执行性能更高一些,而且代码更整洁。
 * switch var1 {
 *     case val1:
 *         ...
 *     case val2:
 *         ...
 *     case val3:
 *         ...
 *     default:
 *         ...
 *
 * var1变量可以是任意的变量类型
 */
func main() {
	//中文的星期几,输出对应的英文
	day := "星期三"
	switch day {
	case "星期一":
		fmt.Println("Monday")
	case "星期二":
		fmt.Println("Tuesday")
	case "星期三":
		fmt.Println("Wednesday")
	case "星期四":
		fmt.Println("Thursday")
	case "星期五":
		fmt.Println("Friday")
	case "星期六":
		fmt.Println("Saturday")
	case "星期日":
		fmt.Println("Sunday")
	default:
		fmt.Println("Unknown")
	}

	//还有更灵活的switch用法
	score := 95
	switch {
	case score < 60:
		fmt.Println("E")
	case score >= 60 && score < 70:
		fmt.Println("D")
	case score >= 70 && score < 80:
		fmt.Println("C")
	case score >= 80 && score < 90:
		fmt.Println("B")
	case score >= 90 && score < 100:
		fmt.Println("A")
	default:
		fmt.Println("Unknown")
	}

	//还有可以这样用switch
	count := 90
	switch count {
	case 60, 70, 80:
		fmt.Println("Ordinary")
	case 90:
		fmt.Println("Excellent")
	default:
		fmt.Println("Unknown")
	}
	
}

运行结果:

跳转链接:

下一篇:二、容器、go编程思想

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527560.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开启自主创新基础设施领先之路,超融合缘何能担当大任?

数字基础设施领域最重要的趋势都有哪些&#xff1f; 毫无疑问&#xff0c;超融合便是其中之一。Gartner《2022年中国ICT技术成熟度曲线报告》&#xff08;Hype Cycle for ICT in China, 2022&#xff09;预测&#xff0c;超融合技术未来2年内将到达“生产力成熟期”&#xff0…

2023企业数智化财务创新峰会西安站圆满举办

5月11日&#xff0c;“初夏之际从头越&#xff0c;数智财务待有时。”由用友主办的「智能会计 价值财务」2023企业数智化财务创新峰会 西安站圆满举办&#xff01;西安交通大学管理学院副院长、教授、博士生导师田高良&#xff0c;山东高速集团有限公司财务共享中心收入核算部…

面向Java开发者的ChatGPT提示词工程(2)

在这篇博客文章中&#xff0c;我将分享一些关于提示词的关键原则&#xff0c;帮助你在使用语言模型时获得更好的结果。具体来说&#xff0c;我将介绍两个关键原则&#xff0c;帮助你编写有效的提示词。同时&#xff0c;我也鼓励你在阅读文章的过程中运行代码&#xff0c;亲自体…

浅谈IDC数据中心综合布线第二篇——结构化布线

数据中心网络在当今的业务中扮演着越来越重要的作用&#xff0c;提供数据的存储、管理、共享、交换、应用等功能。在数据中心中&#xff0c;大量的数据在服务器、交换机、存储设备之间通过物理层的光缆&#xff08;仅讨论光纤布线&#xff09;进行传输。数据表明&#xff0c;在…

java Collection 所有单列集合的父接口

为了在程序中可以保存数目不确定的对象或数据&#xff0c; Java提供了一系列特殊的类&#xff0c;这些类可以存储任意类型的对象&#xff0c; 并且长度可变&#xff0c;这些类被统称为集合。集合类都位于java.util包中&#xff0c; 使用时必须导包。集合按照其存储结构可以分为…

微信小程序开发之获取用户信息

环境 微信开发者工具 Stable 1.06.2303220云开发控制台 v1.5.47 用户的openid和头像名称信息 openid 是小程序用户的唯一标识。注意&#xff0c; openid 并不是微信用户的唯一标识&#xff0c;它是和小程序绑定的。也就是说&#xff0c;同一个微信用户&#xff0c;他在小程序…

【Unity-UGUI控件全面解析】| Dropdown 下拉菜单组件详解

🎬【Unity-UGUI控件全面解析】| Dropdown 下拉菜单组件详解一、组件介绍二、组件属性面板三、代码操作组件四、组件常用方法示例4.1 监听开关事件4.2 添加删除节点💯总结🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉 �…

alembic迁移

alembic 作用 alembic是sqlalchemy的作者开发的。用来做OMR模型与数据库的迁移与映射。alembic使用方式跟git有点了类似&#xff0c;表现在两个方面。 第一个&#xff0c;alembic的所有命令都是以alembic开头 第二&#xff0c;alembic的迁移文件也是通过版本进行控制的。首先…

java版Spring Cloud+SpringBoot+mybatis+uniapp b2b2c 多商户入驻商城 直播 电子商务

J2EE企业分布式微服务云快速开发架构 Spring CloudSpring Boot2MybatisOauth2ElementUI 前后端分离 1. 鸿鹄Cloud架构清单 2. Commonservice&#xff08;通用服务&#xff09; 通用服务&#xff1a;对spring Cloud组件的使用&封装&#xff0c;是一套完整的针对于分布式微…

程序员加班一周总结出可视化大屏效果,9种炫酷组件打包带走!

前段时间参加行业分享交流会&#xff0c;听各位大佬的经验传授&#xff0c;其中有一位用一个极度炫酷的可视化大屏进行展示&#xff0c;可谓是让人眼前一亮。我总是在冲浪的时候看到大屏内容&#xff0c;现场的亲眼目睹大屏真是无比震撼的&#xff0c;于是我马上抓住机会向人家…

Quarkus + mybatis + mybatis-generator 使用总结

Quarkus mybatis mybatis-generator 使用总结 大纲 1 Quarkus结合mybatis 2 Quarkus手动配置数据源 3 Quarkusmybatis的使用 4 使用mybatis-generate 5 使用mybatis-generate后的问题 基础说明 1 开发环境 window112 GraalVM 版本22.3.0 3 quarkus 版本 2.13.7.Final4 myb…

【小韬讲存储】——自动精简配置

ChatGPT全球大火 网友们纷纷登陆尝试它的功能 面对五花八门的问题&#xff0c;ChatGPT都能够给出高情商答案 而答案的背后是百TB数据的分析、训练 对于百TB测试数据 企业不会选择一次性购买所需硬件 而是根据实际所需容量进行多次购买 产品背后的百TB数据容量压力 在当前…

火山引擎DataTester:A/B实验平台数据集成技术分享

DataTester的数据集成系统&#xff0c;可大幅降低企业接入A/B实验平台门槛。 当企业想要接入一套A/B实验平台的时候&#xff0c;常常会遇到这样的问题&#xff1a; 企业已经有一套埋点系统了&#xff0c;增加A/B实验平台的话需要重复做一遍埋点&#xff0c;费时费力&#xff1b…

Android Jetpack Compose中derivedStateOf{}与remember{} with keys的区别

Android Jetpack Compose中derivedStateOf{}与remember{} with keys的区别 在这篇短文中&#xff0c;我将清楚地解释derivedStateOf{}和使用带有keys的remember{}之间的区别。阅读完本文后&#xff0c;你将对它们之间的区别有非常清晰的认识。 先决条件 为了理解本文&#xf…

Java实现自定义字段

Java自定义字段 小黄最近在工作中遇到一个比较有意思的需求&#xff0c;在此跟大家分享一下 需求 这个需求是这样的&#xff0c;用户在添加表单时&#xff0c;除了一些固定信息填入之外&#xff0c;还可以自定义一些字段填入&#xff0c;例如一个用户表&#xff0c;默认情况下…

集文字查询、语音识别、拍照识别的垃圾分类系统,多端合一

一、开源项目简介 垃圾识别精灵 是一个 基于 uni-app 开发 微信小程序&#xff0c;使用 SpringBoot2 搭建后端服务&#xff0c;使用 Swagger2 构建 Restful 接口文档&#xff0c;实现了 文字查询、语音识别、图像识别其垃圾分类的功能。 这是一款个人开发的微信小程序&#x…

Python系列之变量和运算符

目录 一、变量 1.1 什么是变量 1.2 变量的特点 1.3 作用域 1.4 变量的命名规则 1.5 变量的定义和使用 1. 变量的定义 2. 两个变量值的交换 1.6 基本数据类型分类 1.7 数据类型转换 1.8 Python是解释型的强类型动态语言 1.8.1 解释型 1.8.2 强类型 1.8.2 动态语言…

Vue3系列——Pinia状态管理库

目录 Pinia 安装、创建 Store 定义Store Option Store Setup Store 使用Store storeToRefs action异步实现 Pinia Pinia是Vue的专属状态管理库&#xff0c;它允许跨组件或页面共享状态&#xff0c;实现和Vuex一样的数据共享&#xff0c;是Vuex状态管理工具的替代品。…

【直播回顾】AIGC产业研究报告2023图像生成篇报告解读

易观&#xff1a;5月9日&#xff0c;易观高级分析师陈晨带来了《AIGC产业研究报告2023图像生成篇》的报告解读&#xff0c;错过直播的朋友敬请观看回顾&#xff01; 图像作为人工智能内容生成的一种模态&#xff0c;一直在AIGC领域中扮演着重要角色&#xff0c;由于图像生成应用…

1135 Is It A Red-Black Tree(超详细注释+46行代码)

1135 Is It A Red-Black Tree 分数 30 全屏浏览题目 切换布局 作者 CHEN, Yue 单位 浙江大学 There is a kind of balanced binary search tree named red-black tree in the data structure. It has the following 5 properties: (1) Every node is either red or blac…