本文原作者为Stephen Nillson,由ZephyrJung翻译,原文链接如下:
https://www.nada.kth.se/%7Esnilsson/go_for_java_programmers/
鉴于水平有限,未免有很多不合适之处甚至错误,欢迎各位批评指证,Github地址在这里,交流请到黑客派社区,更多精彩等你发现

这篇文章是为了帮助Java程序员们迅速的掌握Go语言。

本篇将先用Java程序员耳熟能详的特性举例,然后通过Go片段给出一些相对细节的描述,最后给出一个没有直接Java代码对应的说明例子。

Hello Stack (example)

为了激发你的兴趣,我们将以一个麻雀虽小五脏俱全的典型案例开始,即Stack.java

Go语言实现如下:

  1. // Package collection implements a generic stack.
  2. package collection
  3. // The zero value for Stack is an empty stack ready to use.
  4. type Stack struct {
  5. data []interface{}
  6. }
  7. // Push adds x to the top of the stack.
  8. func (s *Stack) Push(x interface{}) {
  9. s.data = append(s.data, x)
  10. }
  11. // Pop removes and returns the top element of the stack.
  12. // It’s a run-time error to call Pop on an empty stack.
  13. func (s *Stack) Pop() interface{} {
  14. i := len(s.data) - 1
  15. res := s.data[i]
  16. s.data[i] = nil // to avoid memory leak
  17. s.data = s.data[:i]
  18. return res
  19. }
  20. // Size returns the number of elements in the stack.
  21. func (s *Stack) Size() int {
  22. return len(s.data)
  23. }
  • 在最顶部声明上的注释是文档注释,用纯文本书写
  • 声明的名字写在type之后
  • struct类似于Java中的class,但struct中的成员不能是方法,只可以是变量
  • interface{}类似于Java中的Object。不过它被所有的Go类型实现,不仅仅是引用类型。
  • 代码段(s *Stack)声明了一个方法调用者s,类似于Java中的this
  • 操作符:=同时声明并初始化变量,类型通过初始化表达式的值进行推断
  • 如下是一个Hello World程序,展示如何使用collection.Stack这个抽象数据类型。
  1. package collection_test
  2. import (
  3. collection "."
  4. "fmt"
  5. )
  6. func Example() {
  7. var s collection.Stack
  8. s.Push("world")
  9. s.Push("hello, ")
  10. for s.Size() > 0 {
  11. fmt.Print(s.Pop())
  12. }
  13. fmt.Println()
  14. // Output: hello, world
  15. }

这个cllection_test测试包与collection包的位置在同一目录下。第一个import声明意味着我们将使用当前目录(“.”)下的包,并赋予一个别名collection。第二个声明包含指向标准包路径(“fmt”);如果没有指定别名,则实际包名fmt将作为默认名称。

概念上的区别
  • Go没有带构造器的类,实例方法,继承层次结构,动态方法查找,取而代之的是structs和interfaces。Interfaces也可以用在类似Java的泛型的地方。
  • Go提供任何类型的值的指针,不仅仅是对象和数组。对于任何类型T,都有一个对应的指针类型*T,表示该类型值的指针。
  • Go允许任意类型上的方法,无需装箱。方法的调用者(类似于Java中的this),可以是一个值或一个指针。
  • 在Go中,数组属于数值。当数组被用作方法参数时,方法接收到的是一个数组的拷贝,而非指针。然而实践中,方法经常使用slices作为参数。slices是对数组的底层引用。
  • 语言内置支持字符串, a string behaves like a slice of bytes, 但它是不可改变的。
  • 语言内置支持哈希表,称为map
  • 单独执行线程,goroutines,以及线程之间的通信渠道,channels,都被Go语言内置支持。
  • 特定类型(maps,slices,channels)是通过引用而非值传递的。这就是说,想方法传递一个map类型并不是传递了map的拷贝。如果方法改变了这个map,方法外部调用者也会看到。用Java来讲,可以把这个想象成map的引用。
  • Go提供了两种访问级别,与Java的public和package private类似。名称首部为大写时代表public,否则为package-private
  • 并没有使用exceptions,Go使用了error类型来代表注入到达文件末尾之类的事件,以及运行时panics来代表注入试图越界读取数组的运行时错误
  • Go不支持隐式类型转换。包含不同类型的表达式需要进行显式转换
  • Go不支持方法重载。函数和方法在同一作用域内必须有不同的名称
  • Go用nil代表错误的指针,类似于Java的null

语法

  • 声明

声明语法与Java正好相反,将类型写在名称的后面。类型声明从左往右读可能更容易点儿。

GO Java
var v1 int int v1 = 0;
var v2 *int interger v2 = null;
var v3 string String v3 = “”;
var v4 [10]int int[] v4= new int[10];
var v5 []int int[] = null;
var v6 *struct {a int} C v6 = null; // Given:class c {int a;}
var v7 map[string]int HashMap v7 = null;
var v8 func(a int) int F v8 = null; //interface F {int f(int a)};

var(声明通常是以关键字后面跟随着被声明的对象名称的形式,关键字可能是const,type,var,或func。你可以用一个关键字把一系列的声明写在括号内。

  1. n int
  2. x float64
  3. )

当声明一个方法时,你必须要么为所有参数提供名称,要么一个名称也不写,不能忽略了一些命名,而又提供了另一部分的名称。可以对相同类型的名称进行分组:

  1. func f(i,j,k int,s,t string)

变量可以在声明的时候初始化。如果初始化了,仍然可以进行类型定义但是没有必要,它将默认位初始化表达式的值类型。

  1. var v9=*v2

如果变量没有被显式初始化,那么必须要指定类型。防止它被隐式初始化为零值(0,nil,””,等)。Go里没有未初始化的变量。

分类: web

标签:   golang