1 go的整体思想
go不同于C++ java 语言,使用对象、属性、继承、多态来组织整个程序结构。
go的风格整体倾向于js,python,js两大特点,一是原型链 二是聚合 优于 继承,面向对象带来好处的同时,带来了臃肿和藕合问题,go尝试用包的方式变轻快。
实际上现代语言没有革命性的创新,都是对同样问题的不同解决方式,好的语言特性大家会使用,其他语言实现不好的地方,想办法改进。
2 go 语言没有类
但是go语言使用包(package)来维护代码访问,这个风格与面向对象不同。
java:
import com.****.test.UserInfo;
UserInfo userInfo = new UserInfo;
userInfo.setName("****");
String strName = userInfo.getName();
go:
import (
"com.****.test"
)
test.setName("****");
vale := test.getName
这里使用package.func 就是使用包来组织函数。
问题:
1个package下边可能有多个文件,这个函数不知道在哪个文件中,可以点击代码跟踪过去,但是不够直观。
3 go语言的import
import (
"fmt"
testgin "github.com/gin-gonic/gin"
_ "testgo1/app/api"
)
1 指定包的别名
testgin
2 前面有一个下划线 _
这个表示,只引入包,并且在初始化是调用包内的 init函数,但是并不需要访问别的代码。
4 init函数
go 保证各代码文件中的init函数只被调用1次
go 会分析文件之间的import关系,从而决定先调用那个init,后调佣那个init
init 函数的调用,限于其他函数,可以在init中做变量的初始化工作
5 go.mod
这是工程的配置文件,在这个文件中维护如下信息
module testgo1
go 1.16
require (
github.com/Shopify/sarama v1.30.0 // indirect
github.com/gin-contrib/zap v0.0.1
github.com/gin-gonic/gin v1.6.3
github.com/mitchellh/go-homedir v1.1.0
github.com/seanlan/packages v0.1.0
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.8.1
go.uber.org/config v1.4.0
go.uber.org/zap v1.17.0
)
工程的名字,或者说自己的工程的包路径,用于程序内部引入其他包时的路径前缀
使用的go语言的版本引入的三方库的地址 和 版本,统一在这里配置
这类似于java的pom.xml, python的 main.spec, swift的 Podfile
6 vendor机制
vendor机制,用于维护go工程的三方库,具体的做法是:
0 在工程根路径下建vendor文件夹
1 在go.mod中配置三方库url和版本
2 执行go mod vendor
然后,就会下载三方库,并放到vendor目录下,thinkphp也有vendor路径,用途相似
3 go会优先使用vendor下的库,而不是仓库中的三方库
4 vendor的目的是保留三方库的版本代码,作为特定版本的副本使用
go mod vendor 的机制,和iOS开发pod 很像 Podfile 和
pod install 会生成新的工程,而且会下载三方库到本目录的 pods 文件夹下
这种机制,简单而高效
我们也看下python3的类似机制
// 这句能在工程路径下生成 venv文件夹,并且包含纯净的当前版本 python环境
python3 -m venv myProject
// 下面这句,把环境切换到虚拟环境
source ./myProject/bin/activate加载虚拟环境环境变量
// 安装linux依赖,并且把依赖包安装到了虚拟环境
// myProject/lib/python3.8/site-packages/文件夹下
pop install redis==3.5.1
// 退出虚拟环境
deactivate
7 func 函数
func GetValue(code *int, info string) (left *int, fight int) {
if code == 1 {
return 1, 1 // 直接返回值,不使用返回变量名
}
if code == 2 {
left = 2
right = 2
return // 使用返回变量名字
}
if code == 3 {
left1 = 3
right = 3
return left1, right1 // 使用替换掉的返回变量名
}
1 可以有多个返回值,类似swift中的元组的概念
2 返回值和传参,都可以使用指针
3 func 关键字,在C++ 和 java中都是不使用的
8 变量的名字 方法名字 大小写
go 约定:
首字母大写的变量 和 函数,相当于其他语言的 public
首字母小写的变量 和 函数,相当于其他语言的 private
9 结构体
1 基本概念
就像C语言一样,虽然不继承和多态,封装的思想是必要的。
type JsonResponse struct {
Code int
Message string
Data interface
}
2 方法接收器
func (jsonRes *JsonResponse) getMesage() string {
return jsonRes.Message
}
func (jsonRes *JsonResponse) setMesage(msg string) {
jsonRes.Message = msg
}
我们可以看出,都是对结构体成员的操作的方法。
jsonRes 称为接收器,这样的方法类似面向对象的类和方法,同样思想的变种。
3 方法的本质
类似于C++与C的关系,把this作为函数的第一个参数。
编译器会把 接收器 作为函数的第一个参数,这样方法就是把接收器作为第一个参数的 普通函数
js 和 python都是这样干的,其他语言引入面向对象思想的时候,就把this封装成第一个参数,类似python干脆要自己写,都不隐藏。
10 defer 语句 与 java finally
java 一般 try{} finally 或则 try catch finally,都是连在一起用的。
go defer 不与try 一起使用。
defer 用在函数内部,保证无论panic 还是 return,出函数之前,都会执行 defer 后面的语句
如果有多个defer函数,按照压栈的顺序,后进先出。
func a(){fmt.Println("funca")}
func c(){
defer func a()
defer func b(){fmt.Println("funcb")}()
fmt.Println("func c")
}
11 接口与实现接口
1 接口可以定义一组方法,不定义实现
举例子:
type TestInterface1 interface {
func method1(i int) int
func method2(str string)
}
2 interface{} 类似java的根类,Object,如果函数接受一个interface{}类型的参数,可以当未知类型使用,传什么参数都可以。
3 go对接口 和 实现类之间,采用松散的约定方式
go 采用组合的方式,解决继承的问题。所以,go并没有 extends public impliment 等这样的关键字 放在类名字的后面,也没有class
go一个类型的方法集合 是 接口方法集合 的超集。我们就说它实现了这个接口。编译器在检查的时候,就不会报错。
从程度来讲,这并不像面向对象 extends 那么直观。没办法,使用组合就会这样,你也会享受松散的好处。
12 tag
tag类似于java 的注解,java的注解分为注解的声明 和 注解的 解释器,这个过程会用到反射。
go 的tag类似,用到struct字段后边,去获得额外的信息。
1 tag是结构体的一部分
tag 和结构体的字段一起使用,并基于反射发挥作用
2 tag基本规则
tag是字符串,放在结构体字段后边。
tag以反引号 ``包围,key:value 形式,value要用""包围,冒号两边不能有空格。
举例:
type PayServer struct {
ServerName string `key1:"value1 key2:"value2"`
ServerIP string `key1:"values1"`
}
func main(){
s := PayServer{}
st := reflect.TypeOf(s)
field1 := st.Field(0)
fmt.Printf("key1:%v\n", field1.Tag.Get("key1"))
}
可以看出,这里relect使用的场景,解析的方式。
场景是受限的,解析方式是简单的。可能觉得java反射太复杂了,go也不是解释执行的,只把最常用的部分实现就可以了。
13 go import
go import 有点类似 python 的import
python的class写法,明显是一种封装,非常形式主义
go为了支持类似的功能,搞出来了接收器,也是一种解决方案
python 的 from *** import ***
import (
"fmt"
"github.com/seanlan/packages/gjson"
"io/ioutil"
"net/http"
)
go用的是/,不是.
14 go const
const (
BASE_URI = "http://card.com:8081"
)
15 map 及 遍历
var params = map[string]string{
"123":"456",
"789":"33444",
}
for k, v := range params {
uri = uri + k + "=" + v + "&"
}
go里边的map,结合 interface{},有点类似php中的map,啥都能放,一个map使用范围极广。
16 go 变量
var a int32
b := 5
两种形式,一种声明形式的,一种简写,声明并赋值
17 函数的多个返回值
java 函数只有一个返回值,使用起来极不方便,因为很多时候,你希望有两个返回值,比如网络请求,成功了使用response返回,错误了试用error回复失败的原因。
为此,springframework还发明了 Pair,但这都不是语言层面的支持。
go 在语言层面支持了任意数量的返回值,就非常方便,比如:
func GetShopList(lng float64, lat float64, categoryId int32, startIndex int32, sortType int32) (gjson.JsonObject, error) {
这就明确告诉你,要么处理json,要么通过error取错误原因
上面关于go的总结,并不是像其他的书那样,罗列的入门的知识。二是已经熟悉java C++ python等语言的基础上,通过对比的方式学习go语言。
声明:我要去上班所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,版权归原作者用户9724805569861所有,原文出处。若您的权利被侵害,请联系删除。
本文标题:(go语言)(go语言官网)
本文链接:https://www.51qsb.cn/article/m8c0r.html