香港公司怎么做网站/深圳网站建设服务
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 = 10b := 10//错误func Test(){s := 10s := "test"//错误
}
复制代码
PHP是弱类型编程语言,声明变量时,可以不指定变量的类型,由语言自己推导,但在之后该变量仍然可以被赋于其他类型的值
$a = 10;$a = "test";
复制代码
for、if和switch
for
语句、if
语句和switch
语句的条件体都不需要加括号()
for i := 0; i < 10; i++ {}i := 10if i == 10 {}
x := 10switch 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 = 90switch 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 mainimport "fmt"func main() {switch {case false:fmt.Println("1、case 条件语句为 false")fallthroughcase true:fmt.Println("2、case 条件语句为 true")fallthroughcase false:fmt.Println("3、case 条件语句为 false")fallthroughcase true:fmt.Println("4、case 条件语句为 true")case false:fmt.Println("5、case 条件语句为 false")fallthroughdefault: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 myvar Username string = "test"var age int = 20const Test = "test"const t = 123复制代码
b.go
package myfunc GetUsername() string {return Username
}func GetAge()int{return getAge()
}func getAge()int{return a
}复制代码
main.go
package mainimport "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 Personnumber 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 {Personnumber 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 Readerr = &File{}n, err := r.Read([]byte("test"))if err != nil {panic(err)}fmt.Println(n)//输出:10
}复制代码
自定义类型
Go支持在已有的类型上定义新的类型
package mainimport ("fmt"
)type cm intfunc (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 Readervar i cm = 10fmt.Println(i.Format()) //输出:10厘米r = im, 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 mainimport "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语言社区有大量功能单一但很强大的第三方,使得我们可以根据自己的需要,按需使用第三方库组装自己的项目。
作者:程序员读书
链接:https://juejin.cn/post/7055217931344429093