前言
对于在mac上迁移到windows平台的朋友们来说,windows环境上缺少linux可用环境,经常用起来恼火。本系列文章主要介绍一下自己在搭建一套舒适的linux环境过程中踩过的坑。
工程师,设计师,异想天开症患者
对于在mac上迁移到windows平台的朋友们来说,windows环境上缺少linux可用环境,经常用起来恼火。本系列文章主要介绍一下自己在搭建一套舒适的linux环境过程中踩过的坑。
这是一篇关于go的随笔,旨在记录Java程序转型Go过程中的一些感悟,会记录Go语言一些与Java的差异,一些自己觉得优秀的设计思路,以及Go语言的坑点。
Java通常来说在编译过程中需要遍历依赖链中所有依赖的库。Golang编译器只会关注那些直接被引用的库。 通常来说Go的编译速度不到1秒,在研发过程中更具有优势。
原生的go语言就是为并发设计的,goroutine(类似线程)和channel(线程间的数据共享)的设计方式让程序员可以更轻松的写出处理高并发且线程安全的代码。但通常如果只是写业务代码的话,其实用到的不太多。如果开发框架可以认真看看
面向对象设计的三大特性封装
,继承
,多态
在Java语言中都有体现。但在Go语言中,原生设计舍弃了继承
而使用了组合
这个思路。
通常我们在Java讲面向对象的教程中,如果我们设计一个车,那么就有如下的关系。但在Go语言中,由于组合
的特性,Go语言更倾向于对行为进行建模。在设计过程中更加简单灵活,在使用领域驱动设计的方法时更贴合。
下面关于接口的说明会更加详细的说明这个设计方式
个人觉得这是Golang的一个亮点。 之前Java格式到底何时换行,是否空行等等每个人有每个人的看法。有闲心调格式的时候还行,一旦项目时间紧张,可能最多用IDE直接格式化一下就完了。如果有人不做,那么Java代码就是一团乱,看着闹心。
go fmt
直接提供了代码格式化能力,强制大家用一样的代码风格,阅读性更强。
Java中通常以类为访问的最小单元,如XXXService.getXxx()
, XXXController.updateXxx()
在Golang中,通常以包为访问的最小单元。如util里两个go文件
util
|--collections.go
|--strings.go
func main() {
if !util.IsBlank("xxx") { // 用包名访问方法
fmt.Println("字符串不为空")
}
if util.IsEmpty(map[string]string{}) { // 包名访问方法
fmt.Println("映射为空")
}
}
go语言对定义和赋值语法做了较多的精简,通常来说把对象放在前面,类型放在后面,如:
var str string // var表示定义一个变量,类型是string
func hello(str string) { //函数入参也可以这么定义
fmt.Printf("%s str", str)
}
变量初始化通常有两种方式,第一种方式通常用来定义一个空值。这种方式产生的变量并不是像java一样是空指针
var str string // 初始化为""
var isNow bool // 初始化为false
var num int // 初始化为0
var u user // 对user结构体里面的每一个基本对象按照上述类型进行初始化
// 一次定义多个
var (
hello string
num int
isNow bool
)
第二种方式通常用来定义一个带初始化的值
hello := "hello"
num := 123
isNow := true
u := user{
Name: "zhang",
Age: 18,
}
一旦使用:=
对对象赋值之后,就不能再次使用:=
了,否则会编译失败。可以使用=
对对象进行修改
if err!=nil {
fmt.Println(err)
}
// 如果打开文件失败,那么打印错误
if file, err := os.OpenFile(file); err != nil {
fmt.Println(err)
}
类似java中for循环的:
用法
// java中
for(User user : users) {
System.out.println(user)
}
// go中,增加了index表示当前下标
for index, user := range users {
fmt.Printf("index:%d user:%v\n", index, user)
}
特点:定长、访问速度快、连续存储。函数间传递是值传递 定义有三种类型
var nums [3]int // 定义
nums := [3]int{1,2,3} // 初始化
nums := [...]int{1,2,3} // 懒得填长度的初始化
特点:不定长,动态扩容,容量小于1000时翻倍,大于1000增长因子1.25。函数间传递是引用传递 实例
var nums []int // 跟数组类似,只要不写[]中的数字即可
nums := make([]int, 3) // 另一种定义方式,make是一个关键字
nums := []int{1,2,3} // 初始化方法
nums = append(nums, 4) // 添加,没有删除
newnums = nums[1:3] // 序号从1-3的子切片
切片有长度
和容量
两个不同的概念,可以用len()
和cap()
分别获取
有啥用?只有长度达到容量上限时,才会触发扩容。扩容会有性能损耗,所以在初始化时,可以预估一定范围内的容量,尽量少扩容。
切片是由三部分组成
与数组不同的是在复制切片时,通常都是引用复制
特点:键值对,无序,函数间传递是引用传递 定义方式
// 定义
var dict map[string]string // Map<String,String>
dict := make(map[string]string)
// 初始化
dict := map[string]string {"name":"zhang","address":"12"}
dict["hello"]="world" //增加,修改
delete(dict, "hello") //删除
在Java中除了基本类型,所有类型都是Object类的子类。我们之前提过,在Go中没有继承,而使用组合的方式,所以Go中所有对象都是由各种基本类型组成的结构体,以及结构体组成的结构体。
// 结构定义
type user struct {
name string
email string
}
// 组合结构体
type admin struct {
user
string level
}
var lisa user // 定义
var fred admin // 定义
// 初始化
lisa := user {
name: "lisa",
email: "lisa@email.com",
}
// 初始化
fred := admin {
user: user {
name: "fred",
email: "fred@email.com",
},
level: "super",
}
目前业界可以使用的web框架非常多,各有各的优势和缺陷。结合这几年的从业经验,我畅想了一款面向个人开发者、中小型企业可以快速开发上线的web框架的建设原则。可能有的同学会说,我用spring-boot就很快,我用Django也很好,用php直接无敌了。你为什么还要做这些东西?