main函数对比
习惯上,我们学习一门语言都是从hello_world开始。
先使用一个简单的程序,对比下java和go的代码风格,先有个感性认识。
java
1 | package com.yunsheng; |
go
1 | package main |
我们从第一行开始对比
包的概念
java和go都有package这个关键字。即定义包。
在java代码中,写了package com.yunsheng;那么我的代码一定是在目录com/yunsheng下,包名和目录名必须对应。
而在go中,包名和目录名并不要求对应上,当然强烈建议包名和目录名一致。但是同一个目录下的go源代码文件,必须都是相同的package。

看这个源码,包名,目录名,文件名都可以不一样。
此处包名写为main,是因为go的main函数必须运行在名称为main的包里。
main函数是一个go应用的入口,通常我们将main代码包称为程序代码包或命令代码包。(在工程上,通常将main函数放在名为cmd或app的目录下)。将其他的源码包称为库代码包。
特殊规则
有一个特殊规则:一个引入路径中包含有internal目录名的代码包被视为一个特殊的代码包。 它只能被此internal目录的直接父目录(和此父目录的子目录)中的代码包所引入。比如,代码包.../a/b/c/internal/d/e/f和.../a/b/c/internal只能被引入路径含有.../a/b/c前缀的代码包引入。
引入import
这也是两者都有的关键字。
区别在于,java语法简单直接,引入之后,直接使用。没有什么花活。
go就要多说点了
go引入之后,在使用时需要用引入的包名来使用相应的方法,比如
1 | fmt.Println(time.Now()) |
另外,go在imort时可以给包起别名,如
1 | import myfmt "fmt" |
然后在使用时,就可以用别名
1 | myfmt.Println(time.Now()) |
这是一个非常实用的功能。因为我们经常会遇到引入的包方法同名的情况。在java里,我们需要在调用方法时使用全量包名的方式来解决。go显然提供了更优雅的解决方式。
其实这种方式才是go引入包的标准写法。
1 | import "fmt" |
是省略了自定义包名,默认使用引入的代码包的包名。
句点引入
一种特殊的import方式
1 | import ( |
这种方式引入的,在使用时可以省略包名。就好像是自己写的代码一样。
1 | Println(Now()) |
这种方式不推荐使用,因为会使代码的可读性变差。
匿名引入
1 | import _ "fmt" |
这种方式是为了加载一下包,使包中的初始化代码得到执行,进行资源初始化。
除了这种匿名引入,其他引入的包必须被使用。如果只引入而不使用,代码编译报错。这点也和java不同
class类
java的核心理念就是面向对象,所以我们的代码一般情况下都是在一个class里
go中没有明确的面向对象的说法。
go的一等公民是函数。你可以发现,go是通过包的引入来使用函数和变量等资源。
如果非要扯上的话,可以将struct比作java中的class。关于struct以后再说。
main函数
go和java的程序入口都是这个名为main的函数。
从定义上来看,显然go的语法要简洁的多。
go定义的函数没有java的public、protected、private等访问控制修饰符。go通过一种有趣的方式声明属性或方法的访问权限:通过首字母的大小写。大写的就是其他包可访问,小写的就只能包内访问。所以你可以看到fmt调用的Println首字母就是大写的。
go中没有static关键字,也不支持相关的静态概念。
变量声明
两者虽然都是静态语言,但是go却觉有不少动态语言的灵活性。
go声明变量可以省略类型
比如第6行的
1 | var a, b = 1, 2 |
省略了变量的类型,go会根据字面量值是数字,自动推断a,b的类型是int
写全应该是
1 | var a, b int = 1, 2 |
另外,go中声明变量还有一种更简单的方式,称为短声明
1 | a, b := 1, 2 |
关于短变量声明和var声明的一个区别是:
在方法内两者都可以。但是在方法外只能用var声明。
方法返回
go支持多返回值。相比较java而言,这是一个让人写代码很舒服的特性。
go中方法的返回值一般设计为(data,error)这种形式。
如果方法执行异常,通过error返回错误。
如果方法成功执行,那么使用data的数据。
所以,方法的调用者可以通过error来判断方法是否正常执行完成。