您现在的位置是:首页 > 学无止境
一个PHPer眼中的Go语言
转载自:https://juejin.cn/post/7055217931344429093?share_token=453dac3d-bf0c-4b2e-a78d-e4e166911af1
Go语言是二十一世纪的C语言,具有接近C/C++等编译语言的性能,又像脚本语言(PHP,Javascript,Python)一样容易上手学习,背靠Google,有强大的开发团队和活跃的社区。
Go语言的特性
语法简单
语言层面支持并发编程
跨平台编译
自带垃圾回收机制
Go语言语句不需要加分号
package main import "fmt" func main(){ s := "hello world" fmt.Println(s) }复制代码
数据类型
Go是强类型语言,声明变量时,需要指明变量是什么类型
var i int = 10 b := 10//错误 func Test(){ s := 10 s := "test"//错误 }复制代码
PHP是弱类型编程语言,声明变量时,可以不指定变量的类型,由语言自己推导,但在之后该变量仍然可以被赋于其他类型的值
$a = 10; $a = "test";复制代码
for、if和switch
for
语句、if
语句和switch
语句的条件体都不需要加括号()
for i := 0; i < 10; i++ { } i := 10 if i == 10 { } x := 10 switch x{ }复制代码
switch
PHP中的switch语句
$a = 10; switch ($a) { case 10: echo "111"; break; case 20: echo "222"; break; }复制代码
Go的switch语句
func main() { var level string = "B" var score int = 90 switch score { case 90: level = "A" case 80: level = "B" case 50,60,70 : level = "C" default: level = "D" } switch { case level == "A" : fmt.Printf("优秀!\n" ) case level == "B", level == "C" : fmt.Printf("良好\n" ) case level == "D" : fmt.Printf("及格\n" ) case level == "F": fmt.Printf("不及格\n" ) default: fmt.Printf("差\n" ); } fmt.Printf("你的成绩为: %s\n", level ); }复制代码
fallthrough关键字
package main import "fmt" func main() { switch { case false: fmt.Println("1、case 条件语句为 false") fallthrough case true: fmt.Println("2、case 条件语句为 true") fallthrough case false: fmt.Println("3、case 条件语句为 false") fallthrough case true: fmt.Println("4、case 条件语句为 true") case false: fmt.Println("5、case 条件语句为 false") fallthrough default: fmt.Println("6、默认 case") } }复制代码
循环
Go语言不像其他编程一样,支持while
或do...while
语句,也不像PHP一样有foreach
,Go的循环只有for
语句
普通循环
for i := 0; i < 10; i++ { }复制代码
遍历数组(array)、map或者切片(slice)
for k,v := range arr { }复制代码
变量可见性
在PHP中,如果不使用类,并没有什么变量可见性,声明的都是全局变量:
a.php
$a = 10;复制代码
b.php
include_once("a.php"); echo $a;//输出10复制代码
如果使用类,类的成员,由于public,protected,private 这三个来区分成员的可见性。
class A{ public $a; private $b; protected $c; } class B extends A{ }复制代码
而Go语言以包来组织代码的,变量的可见性非常简单,以首字母是否大写包内可见和全部可见
a.go
package my var Username string = "test" var age int = 20 const Test = "test" const t = 123复制代码
b.go
package my func GetUsername() string { return Username } func GetAge()int{ return getAge() } func getAge()int{ return a }复制代码
main.go
package main import "my" import "fmt" func main(){ fmt.Println(my.Username) fmt.Println(my.GetUsername()) fmt.Println(my.GetAge()) fmt.Println(my.Test) fmt.Println(my.age)//错误 fmt.Println(my.getAge())//错误 fmt.Println(my.t)//错误 }复制代码
是否需要编译
Go静态编译型语言,PHP动态脚本语言
由于脚本语言需要由解释器解释执行,所以执行的性能比编译型语言差。
函数返回值
PHP语言与大多数据编程语言一样,函数或方法只支持一个返回值,而Go语言的函数直接多返回值。
func GetFile(path string)(file *os.File,err error){ f,err := os.Open(path) return f,err }复制代码
空白标识符
由于声明变量后不使用会无法通过编译,因为当我们从某个函数接收多个值,但后面又不需要时,可以使用空白标志符。
func GetFile(path string) *os.File{ file,_ := os.Open(path) return file }复制代码
字符双引号
Go语言的字符串类型不支持单引号,而PHP中,单引号或双引号都可以,如:
PHP字符串
$a = ''; $b = ""复制代码
Go字符串
var s string = "" //必须使用双引号复制代码
与Docker的结合
Go程序最终是打包为一个二进制文件,这个文件一般都很小,最多也就是几十M,而我们把可以直接把这个二制文件打包进Docker的镜像中。
但是PHP的项目运行离不开vendor这个存放所有第三方库的文件,这个文件可能很大,可能有几百M,所以使用docker打包PHP项目,镜像会变得非常大。
奇葩的日期格式化
PHP时间与日期格式化
$t = time(); //Y:年份,m:月份,d:日期,H:时,i:分钟,s:秒 echo date("Y-m-d H:i:s",$t);复制代码
Go语言时间与日期格式化
//2006:年份,01:月份,02:日期,15/03:时,04:分钟,05:秒 fmt.Println(time.Now().Format("2006-01-02 15:04:05")) fmt.Println(time.Now().Format("Jan"))//月份 fmt.Println(time.Now().Format("January"))//月份 fmt.Println(time.Now().Format("Monday"))//星期 fmt.Println(time.Now().Format("Mon"))//星期复制代码
异常捕获机制
PHP像其他编程语言一样支持try...catch语句,用于捕获程序中的异常,如:
try{ 主要逻辑代码 }catch(Exception $ex){ 异常处理 }复制代码
Go语言没有try...catch语句,Go语言的开发建议是程序员在开发的时候,返回error类型
func main() { dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { log.Fatal("数据库连接错误") } //主要逻辑代码 }复制代码
如果实在是一定要抛出异常,不让程序继续执行,可以使用panic()函数,然后通过recover捕捉。
func Parse(input string) (s *Syntax, err error) { defer func() { if p := recover(); p != nil { err = fmt.Errorf("internal error: %v", p) } }() // ...parser... panic("报错啦") }复制代码
defer
Go语言的原创,用于函数执行完成后释放资源等后续操作
func main() { f := GetFile("./1.txt") defer f.Close() f.Write([]byte("test")) } func GetFile(path string) *os.File { file, _ := os.Open(path) return file }复制代码
并发
Go从语言层面支持并发,使用go
关键字就可以简单直接创建一个goroutine,也就是协程,协程可以理解为一种轻量级的线程。
func main(){ go func(){ fmt.Println("hello world") }() }复制代码
协程:大小开始只有2KB,可以动态调整,最大可以到达1GB。
线程:固定要2M。
因此Go语言在一台机器创建成千上万的协程,支持高并发。
协程通讯有两种方式,共享内存和channel
面向对象
Go语言不是传统的面向对象编程语言,不支持类或者对象,但可以通过结构体来模拟一个类
type Person struct { name string //小写:不可导出 Age int //大写,可导出 }复制代码
与类不同的是,结构体不支持继承,与继承与相比,更推荐Go开发者使用结构体组合
type Student struct{ p Person number string }复制代码
func main() { s := Student{ p: Person{ name: "test", Age: 10, }, number: "123333", } fmt.Println(s.number) fmt.Println(s.p.name) }复制代码
匿名嵌入
type Student struct { Person number string } func main() { s := Student{ Person: Person{ name: "test", Age: 10, }, number: "123333", } fmt.Println(s.number) fmt.Println(s.name) }复制代码
结构体也可以像类一样定义自己的方法
func (s *Student) Say(){ fmt.Println("My name is:"+s.name) } func (s *Student) getName() string{ return s.name }复制代码
接口
Go与PHP一样也支持接口,但不同的是,在Go语言中,并不是需要显性实现某个接口.
PHP实现某个接口
interface PosterInterface { public function getData(); } class ActivityPosterData implements PosterInterface { public function getData(){ //实现接口 } }复制代码
Go实现某个接口
type Reader interface{ Read(p []byte) (n int, err error) } type File struct{ } func (f *File) Read(p []byte) (n int, err error){ return 10,nil } func main() { var r Reader r = &File{} n, err := r.Read([]byte("test")) if err != nil { panic(err) } fmt.Println(n)//输出:10 }复制代码
自定义类型
Go支持在已有的类型上定义新的类型
package main import ( "fmt" ) type cm int func (c cm) Format() string { return fmt.Sprintf("%d厘米", c) } func (c cm) Read(p []byte) (n int, err error){ return 20,nil } func main() { var r Reader var i cm = 10 fmt.Println(i.Format()) //输出:10厘米 r = i m, err := r.Read([]byte("cm")) if err != nil { panic(err) } fmt.Println(m) //输出:20 }复制代码
项目管理
在PHP中我们使用composer管理项目的依赖包,composer也是社区开发,并不是PHP官方提供的,而Go语言从诞生之初就提供了非常完善的项目管理工具。
工具链
$ go build . //编译 $ go run main.go //直接运行 $ go get github.com/spf13/viper //获取第三方包 $ go fmt //格式化 $ go test //单元测试或性能测试 $ go env //打印Go的环境变量复制代码
Go Module
//初始化 go mod init jinhongtl/lottery //整理模块 go mod tidy //下载依赖包 go mod download复制代码
风格
大括号问题
函数,方法,if,switch,for,在Go语言中任何使用大插号的地方,大括号都不能单独成一行
//正确 func a(){ } //错误,无法通过编译 func b() { } //正确 for i:= 0;i< 10;i++{ }复制代码
命名问题
变量命名使用骆峰式命名
Username username复制代码
包命名建议使用小写字母,并且与目录同名
Web开发方面的区别
框架
PHP有大而全的框架,如Yii,Laravel,这些框架已经帮我们开发了很多直接使用的功能,比较日志打印,数据库ORM操作,队列,Redis读取等功能
在Go语言中,虽然Web开发方面也有类似的框架,但更常用的是根据自己的需求定制开发,比如,我只是简单开发一个Web应用,读取数据库,那么只需要引用相应的第三方库就可以了。
库名 | 作用 |
---|---|
github.com/spf13/viper | 配置读取 |
github.com/spf13/cobra | 命令行框架 |
github.com/spf13/pflag | 命令行参数 |
github.com/gin-gonic/gin | Web框架 |
github.com/go-playground/validator | 数据校验 |
gorm.io/gorm | 数据库ORM |
github.com/robfig/cron | 定时任务 |
github.com/sirupsen/logrus | 日志 |
go.uber.org/zap | 日志 |
github.com/gorilla/websocket | websocket |
github.com/go-redis/redis | Redis |
方式
Go语言只需要几句代码就可以直接创建一个Web服务器,接收HTTP请求,如:
package main import "net/http" func main() { http.HandleFunc("/test", func(rw http.ResponseWriter, r *http.Request) { rw.Write([]byte("test")) }) http.ListenAndServe(":8088", nil) }复制代码
而PHP如果不与nginx或apache配置,单独是无法提供HTTP服务的,PHP的工作方式如下所示:
推荐目录
如果我们要用Go开发自己的应用,推荐下面这个社区用得比较多的目录结构,在此结构的基础,我们可以引用自己需要的第三方库,来定制自己的项目。
├── README.md ├── api ├── assets ├── build ├── cmd │ ├── apiserver │ │ └── main.go │ └── apiauth │ └── main.go ├── configs ├── deployments ├── docs ├── examples ├── githooks ├── init ├── internal │ ├── guess │ ├── lottery │ └── pkg ├── pkg ├── scripts ├── test ├── third_party ├── tools ├── vendor ├── web └── website复制代码
小结
与PHP相比,Go语言开发的程序具有更高性能,可以支持大量的并发,Go语言的代码也有统一的风格,由于完善的工具链,更易进行项目管理,同时,Go语言社区有大量功能单一但很强大的第三方,使得我们可以根据自己的需要,按需使用第三方库组装自己的项目。
文章评论
- 登录后评论
点击排行
-
php-fpm安装、配置与优化
转载自:https://www.zybuluo.com/phper/note/89081 1、php中...
-
centos下postgresql的安装与配置
一、安装(以root身份进行)1、检出最新的postgresql的yum配置从ht...
-
Mysql的大小写敏感性
MYSQL在默认的情况下查询是不区分大小写的,例如:CREATE TABLE...
-
关于URL编码
转载自:http://www.ruanyifeng.com/blog/2010/02/url_encoding....
-
header中的Cache-control
网页的缓存是由HTTP消息头中的“Cache-control”来控制的,常见的...