常见编程语言入门:go

作者: 稀土掘金  更新时间:2021-03-06 01:31:03  原文链接


概述 go的出现主要是在保证c++或java等性能的前提下提升了开发效率,这里可以参考 What is the purpose of the project?。 go的语法主要来自于c family,在此基础上做了大量简化,比如没有class,简单的并发api(goroutine,channel),也因此go的用法和常见语言有比较大的差别,下面以nodejs端的js为例,通过对比对go做一下基本了解。 与js的对比 解释和编译 js是一种解释型语言,为了加快运行效率,node.js中的v8引擎会进行 just-in-time (JIT) 编译,go是一种编译型语言。 类型 由于类型系统的相关概念有争议(弱类型、强类型、动态类型、静态类型语言的区别是什么?),因此这里不会按此分类。 js本身不会有静态类型检查,因此才有了带类型的ts;类型之间可以各种隐式转换,因此也有了大部分语言没有的三个等号的判等===。 go虽然可以声明时不带类型,但自身包含静态类型检查,不能隐式类型转换,可以使用type_name(expression)进行强制转换 面向对象 js支持以原型继承为基础的面向对象,并由class语法糖,go中为了简化使用,不包含class等继承方式,不算是一个真正意义上的面向对象语言(Is Go an object-oriented language?) 多线程 js的官方规范ecmascript没涉及线程相关的概念,但无论是node.js还是浏览器传统上是以单线程为基础的异步事件驱动,但是后来html规范推出了web worker,node.js推出了worker_threads,因此也为多线程提供了原生的支持,而go更是以轻量级线程goroutine和消息传递方式channel而擅长高并发。 语法 js的语法和c语言很相似,go的语法自带lint功能,比如不能存在引入但不用的包。 包管理 js有生态繁荣的npm,它是世界上最大的software registry,且yarn和npm包管理工具十分方便,go使用go modules,使用可参考这里,没有深度使用,这里不多展开。 结构 一个基础的go代码,比如 package main

import "fmt"

func main() { /* 这是我的第一个简单的程序 */ fmt.Println("Hello, World!") } 复制代码 包含以下部分

包声明 声明当前的包名 包引入 启动函数,main函数,类似于c语言的main函数。

数据类型 包括基本数据类型和派生类型,其中前者包括

布尔型 数字 字符串

后者包括

指针 数组 切片 结构 函数 接口 map channel

布尔型 布尔类型(bool)只有true和false两个值 数字类型 数字类型在go中分的很细,处理传统的int,还有长度的整数和浮点数以及复数。 字符串 字符串(string)类型就是字符组成的数组,即[]rune或[]byte用双引号,其中rune和byte表示单个字符,用单引号。 指针 go中的指针是阉割版的,可以使用&取址,声明指针,指针赋值,除了不能进行运算其他和c语言类似 数组 go中的数组和c语言类似,用来存放定长数量的某种类型,可以用...表示数组长度,编译器根据元素个数推论,但数组名是值类型,不是指针 var variable_name [SIZE] variable_type 复制代码 切片 就是动态数组,可以用未指定长度的数组定义 var identifier []type 复制代码 或者用make var slice1 []type = make([]type, len) 复制代码 结构 还是类似于c语言,用struct关键字 type struct_variable_type struct { member definition member definition ... member definition } 复制代码 结构体指针同样使用点来访问成员 结构可以直接初始化,或者使用new,比如 type user struct { id int 1123 } 复制代码 b := user{} b.id = 222 c := new(user) c.id = 333 复制代码 函数 函数使用func关键字定义,参数列表包括参数类型、顺序和个数,函数名和参数列表构成了函数签名。 func function_name( [parameter list] ) [return_types] { 函数体 } 复制代码 比如 func swap(x, y string) (string, string) { return y, x }

复制代码 接口 c++等面向对象的语言使用class封装数据和方法,go中可以使用结构、接口和函数和创建一个自定义的数据结构。 接口类型可以定义一组方法,用interface关键字,其他类型只要有这些方法就相当于实现了该接口。 结构可以定义一组数据,然后使用函数实现接口的对应方法,完成数据的封装。比如 package main

import ( "fmt" )

type Phone interface { call() } type NokiaPhone struct { } func (nokiaPhone NokiaPhone) call() { fmt.Println("I am Nokia, I can call you!") } type IPhone struct { } func (iPhone IPhone) call() { fmt.Println("I am iPhone, I can call you!") } func main() { var phone Phone phone = new(NokiaPhone) phone.call()

phone = new(IPhone)
phone.call()

} 复制代码 map map就是字典,存储无序键值对 channel 使用chan关键字,用于两个goroutine之间传递消息。 变量和常量 变量 变量声明方法有好多

使用var,其中类型在变量名后面,如果没有类型,编译器会根据后面的初始值推断

var v_name v_type v_name = value 复制代码 如果有类型没有初始值,会初始为零值,零值对于不同类型有不同含义,对于数值初始为0,对于布尔值初始化为false,对于字符串初始化为"",其他一般初始化为nil

省略var,使用:=根据后面的初始值判断类型,用在函数内

v_name := value 复制代码

多变量声明

//类型相同多个变量, 非全局变量 var vname1, vname2, vname3 type vname1, vname2, vname3 = v1, v2, v3

var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断

vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误

// 这种因式分解关键字的写法一般用于声明全局变量 var ( vname1 v_type1 vname2 v_type2 ) 复制代码 常量 常量使用const,只能是基本类型,iota是一个特殊常量 作用域 主要包含函数作用域和全局作用域 语句 条件语句 if语句,除了小括号可以省略基本和js一样 if 布尔表达式 { /* 在布尔表达式为 true 时执行 / } 复制代码 if 布尔表达式 { / 在布尔表达式为 true 时执行 / } else { / 在布尔表达式为 false 时执行 */ } 复制代码 switch,每个case后默认带break,如果不需要可以使用fallthrough switch var1 { case val1: ... case val2: ... default: ... } 复制代码 select语句是通信中使用的switch 循环语句 for循环可以使用range迭代数组(array)、切片(slice)、通道(channel)或集合(map),有三种形式 第一种和js中的for一样 for init; condition; post { } 复制代码 第二种和js中的while一样 for condition { } 复制代码 第三种就是无限循环类似于for { } for { } 复制代码 使用range时,以字符串为例 strings := []string{"google", "runoob"} for i, s := range strings { fmt.Println(i, s) } 复制代码 其中i代表index,s代表value

完结