go|基础语法学习总结

文章探讨了长期从事Java开发的程序员有意愿学习Go语言的原因,主要在于Go语言的并发原生支持、轻量级线程和高效的调度机制,以及相对Java更为简洁的语法。Go的CSP模型和内置的channel机制提供了更好的并发处理方式,同时,Go语言的设计哲学强调简洁和内置生态,有助于提高开发效率和优化资源占用。
摘要由CSDN通过智能技术生成

已经在java领域学习和工作多年的人,为什么有想要探索一门新语言的想法?

  1. 多语言对比学习,更有利于对语音的某些特性有更深的理解
  2. 毫无疑问当前java生态业界无敌,但是不变的只有变化,随着云原生的进一步普及,在十年、二十年后谁也不能保证java的地位仍然固若金汤。所以,在自己精力允许的情况下,积极拥抱另一种语言不是一种坏事。
  3. java语音面临诸多问题,比如但不限于:启动慢、占用资源多、语法不够简洁等
  4. 语言会影响开发者的代码逻辑和业务实现思维方式。go语音作为面相工程的语言,在c的基础上结合既往项目中遇到的问题,并尝试解决他们。这是一种积极和前卫的探索方式,比如说go相对于其他语音的区别类似于springmvc和springboot的区别,后者更加人性化,可以更进步提升效率。
  5. go语言的设计原则,简洁、让用户没有选择就是最好的选择、内置生态。
  6. 并发关乎结构,并行关乎执行。

java和go对比
比较项gojava
线程

原生并发,轻量高效

表现在:用户层轻量级线程,不需要操作系统进行调度

以操作系统线程作为承载分解后的代码片段的执行单元,由操作系统进行调度,创建、销毁以及切换代价较大
线程通信方式

CSP(Communicating Sequential Process,通信顺序进程)模型

对于局部情况,优先使用sync.Metex保证同步

共享内存方式(难用、易错)
特点

1. 资源占用小,每个goroutine初始栈仅为2k

2. go运行时自行调度,goroutine上下文切换代价小

3. 原生支持,开发体验更好

4. 内置channel作为goroutine间通信原语

go语言中,函数和方法的区别:

函数:

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

方法:限定了调用者的函数

func (variable_name variable_data_type) function_name() [return_type]{
   /* 函数体*/
}
go基础语法
语法细分语法介绍
语言结构

包声明、引入包、函数、变量、语句&表达式、注释

换行自动分割,不需显示;声明

fmt.Printf        #

fmt.Println      #

数据类型

1.布尔类型

2.数字类型(uint8-uint64、int8-int64、float32、float64、complex64、complex128、byte、rune、uint、int、uintptr)

3.字符串类型

4.派生类型(指针、数组、结构体、channel、函数、切片、接口、Map)

变量

1.指定变量类型,如果没有初始化,则变量默认为零值

定义:var a string = "Runoob"

字符串零值为“”

派生类型零值为nil

2.根据值自行判定变量类型

var d = true

3.函数专用:=赋值操作符

intVal := 1  等价于  var intVal int; intVal =1

赋值操作仅可以在函数体中使用,且无法对同一变量多次操作;

在函数体中声明的所有变量都需要被使用,否则编译报错;

交换两个变量的值  a, b = b, a

空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃

常量

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

常量还可以用作枚举,常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值

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

运算符
  • 算术运算符 + - * / % ++ --
  • 关系运算符 == != > < >= <=
  • 逻辑运算符 && || !

        位运算符对整数在内存中的二进制位进行操作。& |  ^ << >>

  • 位运算符 = += -= *= /= %= <<= >>=  &= |= ^=
  • 赋值运算符
  • 其他运算符

        &a; 将给出变量的实际地址

        *a; 是一个指针变量

条件语句

if...else 语句

switch语句

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

注意:go没有三元运算符

循环语句

for循环

break,中断循环

continue,跳出本次循环,执行下一次循环

goto

函数体

函数定义,例如:

func swap(x, y string) (stringstring) {
   return y, x
}
值传递值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

默认情况下,go使用的是值传递。

Go 语言中同时有函数和方法,一个方法就是一个包含了接受者的函数,例如:

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

数组

初始化:

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 和 3 的元素初始化
balance3 := [5]float32{1:2.0,3:7.0} 

指针

var a int = 10
var aa *int = &a

var ptr *int
fmt.Printf("%x\n", ptr) // 0
fmt.Println(ptr) // <nil>

结构体

数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。

关键字,type struct

type Books struct {
   title string
   author string
   subject string
   book_id int
}

fmt.Println(Books{"name", "author", "subject", 123})
fmt.Println(Books{title: "name", book_id: 123})

切片(slice)

一种灵活,功能强悍的内置类型切片("动态数组")

s :=[] int {1,2,3 }          #直接初始化
s := arr[:]                     #通过引用数组来初始化   
s := arr[startIndex:endIndex]         #通过数组的起始下标初始化【左闭右开】
s1 := s[startIndex:endIndex]          #通过切片初始化另一个切片
s :=make([]int,len,cap)                   #使用内置make函数初始化,[]int 表示为其元素类型为 int 的切片      

// 初始化

numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
fmt.Printf("%v\n", numbers[0:9])

// 追加
numbers = append(numbers, 9)

范围(range)

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

map1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
map1[3] = 3.0
map1[4] = 4.0

// 读取 key 和 value
for key, value := range map1 {
        fmt.Printf("key is: %d - value is: %f\n", key, value)
}

//range 也可以用在 map 的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
}

Map(集合)

可以使用内建函数 make 或使用 map 关键字来定义 Map(参考楼上,range示例代码)

// 获取键值对
v1 := m["apple"]
v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值
// 修改键值对
m["apple"] = 5
// 获取 Map 的长度
len := len(m)
// 删除键值对
delete(m, "banana")
类型转换

var a int = 10
var b float64 = float64(a)

var str string = "10"
var num int
num, _ = strconv.Atoi(str)
接口

Go 语言中的接口是隐式实现的,也就是说,如果一个类型实现了一个接口定义的所有方法,那么它就自动地实现了该接口。因此,我们可以通过将接口作为参数来实现对不同类型的调用,从而实现多态。

// 以结构都定义在包$GOROOT/src/runtime/runtime2.go

非空接口

type iface struct {

        tab *itab        

        data unsafe.Pointer        //  指向动态类型变量的

}

type itab struct{

        inter *interfacetype        // 存储改接口类型自身信息,包括类型、包路径名、接口方法集合切片

        _type *_type                 // 动态类型变量的类型信息

        hash uint32                   

        _         [4]byte

        fun      [1]uintptr             // 动态类型已实现的接口方法的调用地址数组

}

// 空接口

type eface struct {

        _type *_type        // 指向动态类型变量的类型信息

        data unsafe.Pointer        //  指向动态类型变量的

}

在判断两个接口是否相等时,只判断eface._type/iface.tab._type是否相同以及data指针指向的内存空间所存储的数值是否相同,注意不是指针的值。(比较类型和实际数值)

并发

通过 go 关键字来开启 goroutine 即可,goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。

go 函数名( 参数列表 )

通道(channel)是用来传递数据的一个数据结构,线程间的一种通信方式,借鉴于erlang。(其他方式:共享内存、管道、socket、、、、)

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


select

select {

        case x := <-c1:        // 从channel c1接收数据

        ……

        case y, ok := <-c2:        // 从channel c2接收数据,并根据ok判断才是否已经关闭

        ……

        case c3 := <- z:        // 将z值发送到channel c3中

        ……

        default:                    // 当以上channel通信均无法实施,执行改默认分支

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值