GO 语言基础学习记录

news/2024/10/21 11:39:49/

一:声明变量

在golang语言中声明变量的方式

package main

import "fmt"

func main() {
        var a int = 3  //关键字 var + 变量名 + 变量指定类型 = 变量值        

        var b int        //关键字 var + 变量名 + 变量指定类型(注意:当变量没赋值时是按照变量指定类型的默认值进行赋值,如 【var b int】最后输出的就是int类型的0 而【var b bool】则会输出bool类型的false )

        var c = 4        //关键字 var + 变量名 = 变量值(注意:当变量未设置类型则会根据变量值自行补充,如【var c = 4】则c的类型为int 而【var c = "hello"】c的类型则为string)

        var d, e int = 1, 2  //这是在第一个声明的基础上进行多个变量声明

        var f, g int              //这是在第二个声明基础上进行多个变量声明  

        var h, i = 7, 8        //这是在第三个声明基础上进行多个变量声明

        //输出

        fmt.Println(a, b, c, d, e, f, g, h, i)

        //输出的值为 3 0 4 1 2 0 0 7 8
}

注意:在方法中设置变量的时候,一定要在方法体中用到,否则会报错(如果 var c int 在方法中却没有使用,则运行程序会报错!)!! -- go的全局变量不限制,仅校验方法中的变量

go中除了用 var 关键字声明的变量外,还提供了 := 的方式声明未声明过的变量。

package main

import "fmt"

func main() {
       a := 3 

       b := "hellow"

       c, d := 8, "word"

        //输出

        fmt.Println(a, b, c, d)

        //输出的值为 3 hellow 8 word
}

注意::= 只能用于声明 未被声明过的变量( 如声明 var a int  = 3   后再 a := 4  就会报错)

二:声明常量

常量的声明可以参考变量声明的第一部分-此处省略

const a int = 3 //关键字 const + 常量名 + 常量类型 = 常量值

注意:常量在方法中声明不校验是否调用、

除了上面的常量声明方式外,常量还可用作枚举

package mainimport "fmt"func main() {const (Unknown = 0Female = 1Male = 2)//输出fmt.Println(Unknown, Female, Male)//输出值为 0 1 2
}

在常量声明时,可以引入“unsafe” 包使用 函数计算表达式,注意:必须是系统内置函数

package main

import "fmt"
import "unsafe"


func main() {
        const (
                a = "abc"
                b = len(a)
                c = unsafe.Sizeof(a)
        )
        const e string = "abg"
        const f int = len(a)
        const g = unsafe.Sizeof(a)

        //输出
        fmt.Println(a, b, c, e, f, g)

        //输出值为 abc 3 16 abg 3 16
}

 相对于常量声明中 枚举类型 有个 iota 用法 ,就是 从0开始依次递增  

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)
}

三、运算符

go的运算符和其他编程语言基本一致

+(加)、-(减)、*(乘)、/(除)、%(取余数)、++(自增)、--(自减)、==(相等)、!=(不等)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)、&&(与)、||(或)、!(非)等等

这里着重记录一下 位运算 和 其他运算符 (了解即可,日常业务中很少用到)

位运算符:&(二进制相与)、|(二进制相或)、^(二进制相异)、<<(二进制左移)、>>(二进制右移)

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 */ //二进制相与,当二进制码对应位都为1时记录为1
   fmt.Printf("第一行 - c 的值为 %d\n", c )

   c = a | b     /* 61 = 0011 1101 */ //二进制相或,当二进制码对应位有一位为1时记录为1
   fmt.Printf("第二行 - c 的值为 %d\n", c )

   c = a ^ b     /* 49 = 0011 0001 */ //二进制相异,当二进制码对应位值不同时记录为1
   fmt.Printf("第三行 - c 的值为 %d\n", c )

   c = a << 2   /* 240 = 1111 0000 */ //二进制左移,将左侧丢弃,右侧填补为0,<<2就是丢弃两位
   fmt.Printf("第四行 - c 的值为 %d\n", c )

   c = a >> 2   /* 15 = 0000 1111 */ //二进制右移,将右侧丢弃,左侧填补为0
   fmt.Printf("第五行 - c 的值为 %d\n", c )
}

 其他运算符:&(获取变量存储地址)、*(指针变量)

package main

import "fmt"

func main() {
        var a int = 4  
        var ptr *int
        /* & 和 * 运算符实例 */
        ptr = &a /* 'ptr' 包含了 'a' 变量的地址 */
        fmt.Printf("a 的值为 %d\n", a);  //输出a变量的值 4
        fmt.Printf("a 的值为 %d\n", &a); //输出a变量的变量存储地址,能粗浅理解为数据库的索引
        fmt.Printf("*ptr 为 %d\n", *ptr); //输出的是指针变量下的值  4
        fmt.Printf("ptr 为 %d\n", ptr);  //输出指针变量的存储地址
}

在go中也有其他语言的  if、if...else..、switch、等。

也有:for 循环和嵌套,有 break、continue、goto语句。

注意:在go中没有while循环

 四、函数、方法声明和调用

package main

import "fmt"

func main() {
        var a, b int = 4,5
        var c int
        var s string
        c = sum(a,b)
        s = fmt.Sprintf("获取a+b=%d",c)
        fmt.Println(s)
}

func sum(x int,y int) int{   //声明函数 关键字func + 函数名称 + 函数参数和参数类型 + 返回类型
        return x+y
}

注意:声明函数的时候,必须设定参数类型和返回值类型!

 这里记录一下  函数多个返回值 和 函数闭包(匿名函数) 的用法

package main

import "fmt"

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}


func swap(x, y string) (string, string) { //设定两个string类型的返回值
   return y, x
}

package main

import "fmt"

func main() {
    // 定义一个匿名函数并将其赋值给变量add
    add := func(a, b int) int {
        return a + b
    }


    // 调用匿名函数
    result := add(3, 5)
    fmt.Println("3 + 5 =", result)

    // 在函数内部使用匿名函数
    multiply := func(x, y int) int {
        return x * y
    }

    product := multiply(4, 6)
    fmt.Println("4 * 6 =", product)

    // 将匿名函数作为参数传递给其他函数
    calculate := func(operation func(int, int) int, x, y int) int {
        return operation(x, y)
    }

    sum := calculate(add, 2, 8)
    fmt.Println("2 + 8 =", sum)

    // 也可以直接在函数调用中定义匿名函数
    difference := calculate(func(a, b int) int {
        return a - b
    }, 10, 4)
    fmt.Println("10 - 4 =", difference)
}

再记录一下 go 中的方法

package main

import (
   "fmt"  
)

/* 定义结构体 */
type Circle struct {
          radius float64
}

func main() {
          var c1 Circle
          c1.radius = 10.00
          fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
          //c.radius 即为 Circle 类型对象中的属性
          return 3.14 * c.radius * c.radius
}

注意:从上面的例子中我们可以看出,在go中 方法和函数是不同的。方法在定义的时候会在 func 关键字后面  方法名的前面 设置一个接收器( c Circle) 该接收器可在方法中调用

五、变量作用域

函数方法外面的是全局变量,方法或函数内的则是局部变量,局部变量优先级大于全局变量。局部变量除非作为参数传入另一个方法或函数中,否则两个方法或函数中的局部变量不能共用。

六、数组

在go中初始化数组,需要明确个数和类型

var  a [10]int   //初始化数组 关键字 var + 数组名 + [数组元素个数]数组元素类型

var  a = [5]int{1,2,3,4,5} //初始化数组 a 并赋值

a := [5]int{1,2,3,4,5} //省略关键字 var 初始化数组 a 并赋值

var a = [...]int{1,2,3} //省略数组元素个数,通过"..."程序会自动通过赋值确定元素个数

a := [...]int{1,2,3} //和上面同理

var a []int   //设置空切片a  注意:不指定长度的数组都是切片,第七点记录切片

a := []int{}  //设置空切片a

 多维数组也同理  var a [][]int 初始化即可 

package main

import "fmt"

func main() {
        // Step 1: 创建数组
        values := [][]int{}   //创建二维空数组

        // Step 2: 使用 append() 函数向空的二维数组添加两行一维数组
        row1 := []int{1, 2, 3}
        row2 := []int{4, 5, 6}
        values = append(values, row1)
        values = append(values, row2)

        // Step 3: 显示两行数据
        fmt.Println("Row 1")
        fmt.Println(values[0])
        fmt.Println("Row 2")
        fmt.Println(values[1])

        // Step 4: 访问第一个元素
        fmt.Println("第一个元素为:")
        fmt.Println(values[0][0])
}

 七、切片

相较于数组的长度不可改变,go还提供了切片的类型也可以称之为 动态数组,即它的长度不固定,可以直接追加元素提升切片的元素数

通过make()函数来创建切片

var slice []type = make([]type, len)   //注意:len只是定义切片的初始长度 可以为0

slice := make([]type, len)

如:

slice1 := make([]int,0)  //这行代码创建了个长度为0 的slice1 切片

除了用make() 函数来创建切片外

slice2 := []int{} 和 var slice2 []int  也是初始化了一个切片

对于数组来说,切片除了不用固定长度这一个优点外,还有一个切片赋值的功能

package main

import "fmt"

func main() {
        arr :=[]int {1,2,3 }  //初始化一个切片 a  里面有三个值
        s := arr[0:2]          //将切片下标0-2 的值 赋值给s
        fmt.Println(s)        //输出 [1 2] 

        fmt.Println(len(arr)) //
        fmt.Println(cap(arr)) //

}

切片除了通过[:]来获取指定下标的值,由于切片有索引,所以go很多内置函数都可作用于切片上

如:len()//获取切片长度  cap() //计算容量获得切片最大长度

八、range的用法

当需要循环数组、切片、集合等数据时,可以用for + range 的关键字来遍历。

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
for i, v := range pow {     //应用range时,会直接将循环中的key值提供给i,value值提供给v(i,v是变量类型,可以设置成你熟悉的变量名 如:k,v  也可以)
                fmt.Printf("2**%d = %d\n", i, v)
        }
}

除了将 pow 的值完全按照 key-value 的形式完全赋值给 i,v 外,如果只想要key,则可以省略v 如:for i := range pow{  或者用 _ 代替 如  for  i,_  := range  pow { 

当然,如果只想要value 不要key时也可以用 _ 代替 如:   for _,v := range pow{

注意://range也可以用来枚举 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身

 九、map的用法

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的

在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 ""。

Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。

// 创建一个空的 Map
m := make(map[string]int)   

// 创建一个初始容量为 10 的 Map
m := make(map[string]int, 10)

// 使用字面量创建 Map
m := map[string]int{"apple": 1,"banana": 2,"orange": 3,
}
// 获取键值对
v1 := m["apple"]     //map 就和 php中的数组对象类似,用值的时候直接 变量[key值] 即可
v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值

Map很像php 中的数组对象类型,但是Map是引用类型,要注意改变其中一个值时 其他引用过Map的变量都会更改

package main

import "fmt"

func main() {
        s := map[string]string{    //初始化一个map数据
                "one" : "one",
                "two" : "two",
                "three" : "three",
        }
        c := s                                //将 s 赋值给 c
        a := s["two"]                     
        b := s["two"]
        a = "for"
        fmt.Println(a, b, s, c)  //输出值 for two map[one:one three:three two:two]  map[one:one three:three two:two]
        s["two"] = "fiv"
        fmt.Println(a, b, s, c) //for two map[one:one three:three two:fiv] map[one:one three:three two:fiv]
}

从上面的示例可以看出,当将整个map类型的s赋值给c时,修改s 的值,c同样会变化!

delete() 函数可以删除map中的值 delete(map变量,需要删除的key值)

十、变量类型转换

1、数值类型转换

var a float64 = 3.7415926     //定义float64类型a为3.7415926
var b int        = int(a)              //将a转变成int类型赋值给b

fmt.Println(a, b)                     //输出结果 a=3.7415926     b=3   从float转化为int时,会直接舍去小数点后的值

 注意:go 不支持隐式转换类型,比如 :

package main
import "fmt"func main() {  var a int64 = 3var b int32b = afmt.Printf("b 为 : %d", b)
}

会报错

cannot use a (type int64) as type int32 in assignment
cannot use b (type int32) as type string in argument to fmt.Printf

但是如果改成 b = int32(a) 就不会报错了:

package main
import "fmt"func main() {  var a int64 = 3var b int32b = int32(a)fmt.Printf("b 为 : %d", b)
}
2、字符串类型转换
var str string = "10"        //定义字符串str
var num int                  //初始化int类型num
num, _ = strconv.Atoi(str)   //将字符串转换为num的数据类型,其中 _ 位置取的是转换时的错误信息,如果想查看错误信息则需

var msg error                                //定义error类型 msg

num,msg  = strconv.Atoi(str)        //通过 msg 获取转换失败的信息

或者可以用下面方法直接获取:

number, msg = strconv.Atoi(str)   //没有错误时 msg为nil

注意:使用strconv.Atoi() 函数时,要引入  strconv 包

3.接口类型转换

接口类型转换有两种情况:类型断言类型转换

类型断言用于将接口类型转换为指定类型:

value.(T)

 其中 value 是接口类型的变量, T 是要转换成的类型。

如果类型断言成功,它将返回转换后的值和一个布尔值,这个布尔值表示转换是否成功。

package main

import "fmt"

func main() {
    var i interface{} = "Hello, World"                  //定义接口变量i
    str, ok := i.(string)                                        //将i类型断言为字符串类型 返回转换后的值和断言结果
    if ok {        //类型断言成功
        fmt.Printf("'%s' is a string\n", str)
    } else {      //类型断言失败
        fmt.Println("conversion failed")
    }
}

类型转换用于将一个接口类型的值转换为另一个接口类型:

T(value)

T 是目标接口类型,value 是要转换的值。

注意:在类型转换中,我们必须保证要转换的值和目标接口类型之间是兼容的,否则编译器会报错。

package main

import "fmt"

type Write interface { //定义接口Write 接口参数为 []byte类型数据 返回值为 int 和 error类型
        Write([]byte)(int,error)
}

type WriteString struct { //定义结构体WriteString 结构体属性 str 为字符串类型
        str string
}


func (ws WriteString) Write(data []byte)(int, error){ 
        ws.str += string(data)
        return len(ws.str) , nil
}

func main(){
        var w WriteString
        ss := "hellow_Word!"
        sb := []byte(ss)
        fmt.Println(w.Write(sb))
}

 十一、go实现并发

Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。

package main

import (
        "fmt"
        "time"
)

func say(s string) {
        for i := 0; i < 5; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
        }
}

func main() {
        go say("world")
        say("hello")
}

//输出的 world 和 hello 出现的顺序并不固定,也从侧面证明了 使用go关键字后确实 两次方法调用确实没有先后,是处于两条并发线程中

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

package main

import "fmt"

func sum(s []int, c chan int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 sum 发送到通道 c
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}

        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收
        fmt.Println(x, y, x+y)
}

 目前我认为通道的作用 就是用于等待时常 可以同时获取到 两个goroutine 的值。

注意:x和y的值不一定是按照执行代码先后时间来分配的,也就是说x有可能获得第二个结果

 如下面的代码,只要多执行几次,总会获得 *d, *e, *f  依旧会输出 1, 2, 3 的情况 或者 其中几个值是sum 运行后的值,从而证明了 并发并不是执行完goroutine 之后再进行下面代码的执行。

package main

import "fmt"

func sum(s []int, c *int) {
        sum := 0
        for _, v := range s {
                sum += v
        }
        *c = sum
        fmt.Println(" sum中:",*c,"------\n")
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}
        a,b,c := 1,2,3
        d, e, f := &a, &b, &c
        go sum(s[:len(s)/2], d)
        go sum(s[len(s)/2:], e)
        go sum(s[2:len(s)-2], f)
        fmt.Println(" 变量值 ",*d, *e, *f,"------\n")
}

或者我提供另一个佐证   执行这段代码时,会沉睡,直至x和y 接收到结果

package main

import (
        "fmt"
        "time"
)

func sum(s []int, c chan int) {
        sum := 0
        time.Sleep(10 * time.Second) //沉睡十秒
        for _, v := range s {
                sum += v
        }
        c <- sum // 把 sum 发送到通道 c
}

func main() {
        s := []int{7, 2, 8, -9, 4, 0}
        c := make(chan int)
        go sum(s[:len(s)/2], c)
        go sum(s[len(s)/2:], c)
        x, y := <-c, <-c // 从通道 c 中接收
        fmt.Println(x, y, x+y)
}

学习时借助查看 菜鸟教程

网址:Go 语言教程 | 菜鸟教程 


http://www.ppmy.cn/news/1393431.html

相关文章

什么是PLC物联网关?PLC物联网关有哪些功能?

在数字化浪潮的推动下&#xff0c;工业物联网&#xff08;IIoT&#xff09;正逐步成为推动制造业智能化转型的关键力量。而在这一变革中&#xff0c;PLC物联网关扮演着至关重要的角色。今天&#xff0c;就让我们一起走进PLC物联网关的世界&#xff0c;了解它的定义、功能&#…

在云上部署我的个人博客!!!

这和上一篇是连起来的&#xff0c;大家先整体看一遍&#xff0c;不要跟&#xff0c;前面有些弯路&#xff01;&#xff01;&#xff01; 【这是按时计费的&#xff0c;欠费不能用&#xff0c;交了好几次哈哈哈哈 】 【我买的域名是&#xff1a;128.1.61.228】 【把域名这个位置…

gateway网关指定路由响应超时时间

gateway网关指定路由响应超时时间 spring:cloud:gateway:httpclient:responseTimeout: 10000这个配置用于设置HttpClient的响应超时时间&#xff0c;单位是毫秒。具体来说&#xff0c;这个配置表示当Gateway向后端服务发出请求后&#xff0c;如果在10秒内没有收到后端服务的响…

H5 与 App、网页之间的通信

前言 本文整理工作中 H5 嵌入 Android、iOS 与 PC 网页后&#xff0c;如何与各端通信。&#xff08;提供 H5 端的代码&#xff09; 环境判断 const ua navigator.userAgent.toLowerCase()const isAndroid /android/i.test(ua)const isIos /iphone|ipod|ios/i.test(ua)cons…

asp.net mvc 重新引导视图路径,改变视图路径

asp.net mvc 重新引导视图路径&#xff0c;改变视图路径 使用指定的控制器上下文和母版视图名称来查找指定的视图 通过本文学习&#xff0c;你可以根据该技法&#xff0c;去实现&#xff0c;站点自定义皮肤&#xff0c;手机站和电脑站&#xff0c;其他设备站点&#xff0c;在不…

分类预测 | Matlab实现PSO-KELM粒子群优化算法优化核极限学习机分类预测

分类预测 | Matlab实现PSO-KELM粒子群优化算法优化核极限学习机分类预测 目录 分类预测 | Matlab实现PSO-KELM粒子群优化算法优化核极限学习机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现PSO-KELM粒子群优化算法优化核极限学习机分类预测(完整源…

【PHP】通过PHP安装数据库并使数据初始化

一、前言 有些CMS在部署的时候不用使用数据库工具&#xff0c;而是通过数据库安装页面就能完成数据库创建和数据填充&#xff0c;所以自己就想动手做一个这样的功能&#xff0c;这样在给别人安装系统的时候就不用再那么麻烦了&#xff0c;直接一键安装解决了。 二、效果图 输…

yolov6实现遥感影像目标识别|以DIOR数据集为例

1 目标检测是计算机视觉领域中的一项重要任务&#xff0c;它的目标是在图像或视频中检测出物体的位置和类别。YOLO&#xff08;You Only Look Once&#xff09;是一系列经典的目标检测算法&#xff0c;最初由Joseph Redmon等人于2016年提出。YOLO算法具有快速、简单、端到端的特…