hello云胜

技术与生活

0%

main函数对比

习惯上,我们学习一门语言都是从hello_world开始。

先使用一个简单的程序,对比下java和go的代码风格,先有个感性认识。

java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.yunsheng;

import java.util.Date;

public class Demo {
public static void main(String[] args) {
int a = 1;
int b = 2;
Demo demo = new Demo();
int c = demo.sum(a, b);
Date now = new Date();
System.out.println(now.toString());
System.out.println(c);
}

private int sum(int a, int b) {
return a + b;
}
}

go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"time"
)

func main() {
var a, b = 1, 2
result, err := sum(a, b)
if err == nil {
fmt.Println(result)
}
fmt.Println(time.Now())
}

func sum(a int, b int) (int, error) {
c := a + b
return c, nil
}

我们从第一行开始对比

包的概念

java和go都有package这个关键字。即定义包。

在java代码中,写了package com.yunsheng;那么我的代码一定是在目录com/yunsheng下,包名和目录名必须对应。

而在go中,包名和目录名并不要求对应上,当然强烈建议包名和目录名一致。但是同一个目录下的go源代码文件,必须都是相同的package。

image-20220902093338378

看这个源码,包名,目录名,文件名都可以不一样。

此处包名写为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
2
3
4
import (
. "fmt"
. "time"
)

这种方式引入的,在使用时可以省略包名。就好像是自己写的代码一样。

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来判断方法是否正常执行完成。