Java程序员快速入门 go 语言 已翻译 100%

oschina 投递于 2013/07/10 18:17 (共 31 段, 翻译完成于 07-19)
阅读 19265
收藏 282
29
加载中

这篇文章帮助Java程序员快速入门Go语言。

本文将以一个有代表性的例子为开始,以此让Java程序员对Go语言有个初步认识,随后将详细的描述Go语言的各个构成模块,最后以一个例子来讲解Go语言与Java语言的不同点。

yale8848
yale8848
翻译于 2013/07/10 19:21
3

先来认识堆栈(例子)

为了满足大家的好奇心,我们将开始于一个麻雀虽小但五脏内全的例子,这个例子将是Stack.java的Go语言版本。

//实现堆栈的包集合
package collection

//生成空堆栈
type Stack struct {
    data []interface{}
}

//压栈顶
func (s *Stack) Push(x interface{}) {
    s.data = append(s.data, x)
}

//弹栈顶,并删除栈顶
//如果是空栈将会引发运行时错误
func (s *Stack) Pop() interface{} {
    i := len(s.data) - 1
    res := s.data[i]
    s.data[i] = nil  // to avoid memory leak
    s.data = s.data[:i]
    return res
}

//返回栈大小
func (s *Stack) Size() int {
    return len(s.data)
}
  • 用纯文本在声明语句上方添加注释。
  • 申明的名字写在类型的后面。
  • 结构体和Java中类相对应,但结构体的成员只能是变量,不能是方法。
  • interface{}类型对应Java中的Object。它不仅能代表引用类型,同时也能实现Go语言的所有类型。
  • (s *Stack)表示申明一个方法,s对应于Java中方法隐式传的this参数。
  • 操作符:=表示申明和初始化一个变量,其类型由初始化语句决定。
yale8848
yale8848
翻译于 2013/07/10 19:56
3

下面是是使用collection.Stackabstract数据类型的简单例子。

package collection_test

import (
    collection "."
    "fmt"
)

func Example() {
    var s collection.Stack
    s.Push("world")
    s.Push("hello, ")
    for s.Size() > 0 {
        fmt.Print(s.Pop())
    }
    fmt.Println()
    // Output: hello, world
}
将测试包package colloection_test和collectionpackage放在同一目录。第一个import声明“.”表示将要用当前路径中的包并同时命名为collection,“fmt”是标准库的包名,没有重新命名,所以就直接用包名fmt即可。
yale8848
yale8848
翻译于 2013/07/10 20:08
1

概念上的不同点

  • Go没有类的构造器。Go提供结构体接口,类的继承以及动态方法查询来进行实例化,而非通过实例方法。接口同样用于Java中的泛型。
  • Go中不仅对象和数组可以有指向数据的指针,其它所有类型都有。对于任何类型T,都有一个指针类型*T与之相对应,其表明指向类型为T的值。
  • Go允许在任何类型上创建方法;方法的接收者,就是Java中this,可以是个值或是指针。
  • 数组在Go中是一些值。当数组作为函数参数传递时,函数将收到数组值的拷贝,不是指针。然而实际中,经常用slices作为参数;因为切片中有数组的引用。
  • Go中提供字串类型;字串就像是由比特序列构成的slices,但字串是不可变的。
  • 在Go中哈希表叫maps。
  • Go提过channels类型来在多线程,goroutines之间通信来实现并发。
  • 一般类型(maps,slices,channels)传参是引用,不是值。如果传参map,参数不是对map的值拷贝;如果函数里改变了map的值,函数调用者的map也将改变。这个和Java中map类似。
  • Go中访问权限有两种,和Java中public 和包private类似。如果声明的名称首字母大写就是public,否则就是包private。
  • Go用error类型取代Java中的异常,诸如访问文件到结尾、运行时刻panic,数组越界等等。
  • Go不支持隐式类型转换,必须是显式的。
  • Go不支持覆盖。函数名和方法名在同一作用域必须不同。
  • Go用nil表示空指针,而Java用null。
yale8848
yale8848
翻译于 2013/07/12 23:19
3

语法

Syntax Terror

声明

声明的语法同Java比较是逆向的。你写上名字然后再跟着写类型。从左至右的类型声明也许读起来容易些。

Go                            约相等的Java写法
var v1 int int v1 = 0;
var v2 *int Integer v2 = null;
var v3 string String v3 = "";
var v4 [10]int int[] v4 = new int[10]; // v4 is a value in Go.
var v5 []int int[] v5 = null;
var v6 *struct { a int }   C v6 = null; // Given: class C { int a; }
var v7 map[string]int HashMap<String,Integer> v7 = null;
var v8 func(a int) int F v8 = null; // interface F { int f(int a); }

声明一般是采用一个关键字后面跟着被定义对象的名称,这种形式。关键字是const、type、var或者func其中之一。你也可以使用一个关键字后面跟着放在括号之中的一系列声明,这种形式。

var (
    n int
    x float64
)
LeoXu
LeoXu
翻译于 2013/07/12 13:41
3
当声明函数时,你必须为每个参数提供一个名称,或者不为任何参数提供名称;你不能省略一些参数的名称并提供其它参数的名称。你可以用相同的类型来组织几个名字,例如:
func f(i, j, k int, s, t string)
一个变量可以在声明它时初始化值。进行此操作时,可以指定变量的类型,但这并非必需的。当不指定类型时,则默认为初始化表达式的类型。
var v9 = *v2

如果一个变量没有明确地初始化,则必须指定其类型。在这种情况下,它将隐式地初始化为其类型的零值(0,nil 等)。在Go语言中没有其它某些语言中的未初始化的变量。

赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/07/10 20:24
2

短声明

在函数内,可以用 := 进行短声明,比如:

v10 := v1
它等效于:
var v10 = v1

函数类型

在Go语言中,函数是一等公民。Go的函数类型表示有相同的参数和结果类型的所有函数的集合。

type binOp func(int, int) int

var op binOp
add := func(i, j int) int { return i + j }

op = add
n = op(100, 200)  // n = 100 + 200
赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/07/10 20:33
1

多重赋值

Go 允许多重赋值。右边的表达式先被求值然后赋给左边的操作数。

i, j = j, i  // 交换 i 和 j 的值(不用象传统语言中需要第三个临时变量).

函数可以有多个返回值,用参数括号后面的一个括号中的列表表示。返回值通过赋予一个变量列表来存储,如:

func f() (i int, pj *int) { ... }
v1, v2 = f()

空标识符

空标识符用下划线字符表示,它提供了一种方法来忽略由多值表达式返回的某个值,如:

v1, _ = f()  // 忽略f()返回的第二个值.
赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/07/10 20:47
2

分号和格式

不需要担心分号和格式,你可以用 gofmt程序创建一个标准的Go样式。虽然这个样式最初看起来或许有点古怪,但它同任何其它样式一样的好,而且熟悉以后会感觉越来越舒服。

在实践中Go代码使用分号不多。严格说,所有的Go语句都是由分号终止。不过,Go在非空白行的末尾隐式插入一个分号,除非该行明显未结束。这带来的影响是,在某些情况下Go不允许换行符。例如,你不能这么写

func g()
{            // INVALID; "{" should be on previous line.
}

g()后面会插入一个分号,使它成为一个函数声明,而不是函数定义。类似的,你也不能写

if n == 0 {
}
else {       // INVALID; "else {" should be on previous line.
}

 }后面else前面会插入一个分号,导致语法错误。

super0555
super0555
翻译于 2013/07/13 13:44
2

条件语句

Go 不使用括号来包裹 if 语句中的条件,和 for 语句中的表达式, 以及 switch 语句中的值。但另一方面,它必须用花括号来包裹 if 或 for 的执行语句体。

if a < b { f() }
if (a < b) { f() }           // 不需要括号.
if (a < b) f()               // 非法(执行体未用花括号括起来)
for i = 0; i < 10; i++ {}
for (i = 0; i < 10; i++) {}  // 非法(表达式不需要括起来)
此外,if 和 switch 接受一个可选的初始化语句,通常用它建立一个局部变量,如:
if err := file.Chmod(0664); err != nil {
    log.Print(err)
    return err
}
赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/07/10 21:03
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(42)

wangxufire
wangxufire

引用来自“zhcosin”的评论

请不要用“取代”一词好不好,GO是Go,Java是Java,各有各的设计原则,谈不上取代一词,另外,Go的方法权限规则表明,如果你想修改一个方法的权限,只能修改它名字首字母的大小写,那意味着所有调用也不得不修改了。
不会重构吗
独爱剑走偏锋
独爱剑走偏锋
java: 我有庞大的开源社区支持的无数项目 go: 我有var
java: 我有20与年的历史经历大量项目考验 go: 我有var
java: 我有强大的jvm及成熟的gc策略 go: 我有var
秋裤
秋裤
围观
qycms_cn
qycms_cn
go语言,参考了python的语句风格 简写奇葩,而把变量的类别置后,也不它独创 var s string = "cao mb" 这类,as3也有。

奇葩!!!
这个世界不真实
这个世界不真实

引用来自“livehl”的评论

引用来自“ak_birdofprey”的评论

引用来自“sol”的评论

引用来自“李师叔”的评论

引用来自“笑莫问”的评论

引用来自“Glitter”的评论

引用来自“铂金小鬼”的评论

引用来自“sol”的评论

引用来自“zhcosin”的评论

请不要用“取代”一词好不好,GO是Go,Java是Java,各有各的设计原则,谈不上取代一词,另外,Go的方法权限规则表明,如果你想修改一个方法的权限,只能修改它名字首字母的大小写,那意味着所有调用也不得不修改了。

是滴 凡事都有正反两面

胡扯,人民日报就只有正面!

^_^

赞一个

人民日报也有反面,”人民”在反面。

更得赞一个了

更得赞一个了

作死的节奏
要不要转发500边???
chai2010
chai2010

引用来自“倒霉的鼹鼠”的评论

引用来自“chai2010”的评论

引用来自“倒霉的鼹鼠”的评论

引用来自“chai2010”的评论

一般类型(maps,slices,channels)传参是引用,不是值。如果传参map,参数不是对map的值拷贝;如果函数里改变了map的值,函数调用者的map也将改变。这个和Java中map类似。
--
Go中参数都是传值的, 没有引用一说.
就像C语言一样, 不能因为指针有引用的语义, 就说C语言的指针是传引用的.

golang不是所有类型都是值语义的,谁告诉你的golang里函数传参没有引用一说的?

http://golang.org/ref/spec#Calls
After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

明确说明: the parameters of the call are passed by value!

恩,从技术实现上是值拷贝,严谨的说法。这里文章是为了表达达到传引用的预期,虽然意思对了,但是措辞不对,不严谨。从沟通理解上看算是简写吧,也许可以说成“XXX这些内置类型传参是引用效果”。

map和handle的效果是类似的, 如果非要理解成引用不好反驳. 但是, slice就绝对是不是能理解为引用(完全错误). 但是, 如果将map当成一个指针, 一切都是可以统一到值传递的规则下的. 用Go语言必须要知道一些底层结构(特别是slice,C语言的基础是必要的), 不然概念很容易搞错. 要是有机会的话, 我会在914武汉源创汇上和Gophers详细说下这个问题.
刘兰琪
刘兰琪

引用来自“chai2010”的评论

引用来自“倒霉的鼹鼠”的评论

引用来自“chai2010”的评论

一般类型(maps,slices,channels)传参是引用,不是值。如果传参map,参数不是对map的值拷贝;如果函数里改变了map的值,函数调用者的map也将改变。这个和Java中map类似。
--
Go中参数都是传值的, 没有引用一说.
就像C语言一样, 不能因为指针有引用的语义, 就说C语言的指针是传引用的.

golang不是所有类型都是值语义的,谁告诉你的golang里函数传参没有引用一说的?

http://golang.org/ref/spec#Calls
After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

明确说明: the parameters of the call are passed by value!

恩,从技术实现上是值拷贝,严谨的说法。这里文章是为了表达达到传引用的预期,虽然意思对了,但是措辞不对,不严谨。从沟通理解上看算是简写吧,也许可以说成“XXX这些内置类型传参是引用效果”。
chai2010
chai2010

引用来自“倒霉的鼹鼠”的评论

引用来自“chai2010”的评论

一般类型(maps,slices,channels)传参是引用,不是值。如果传参map,参数不是对map的值拷贝;如果函数里改变了map的值,函数调用者的map也将改变。这个和Java中map类似。
--
Go中参数都是传值的, 没有引用一说.
就像C语言一样, 不能因为指针有引用的语义, 就说C语言的指针是传引用的.

golang不是所有类型都是值语义的,谁告诉你的golang里函数传参没有引用一说的?

http://golang.org/ref/spec#Calls
After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

明确说明: the parameters of the call are passed by value!
刘兰琪
刘兰琪

引用来自“chai2010”的评论

一般类型(maps,slices,channels)传参是引用,不是值。如果传参map,参数不是对map的值拷贝;如果函数里改变了map的值,函数调用者的map也将改变。这个和Java中map类似。
--
Go中参数都是传值的, 没有引用一说.
就像C语言一样, 不能因为指针有引用的语义, 就说C语言的指针是传引用的.

golang不是所有类型都是值语义的,谁告诉你的golang里函数传参没有引用一说的?
_Oak_
_Oak_

引用来自“铂金小鬼”的评论

引用来自“sol”的评论

引用来自“zhcosin”的评论

请不要用“取代”一词好不好,GO是Go,Java是Java,各有各的设计原则,谈不上取代一词,另外,Go的方法权限规则表明,如果你想修改一个方法的权限,只能修改它名字首字母的大小写,那意味着所有调用也不得不修改了。

是滴 凡事都有正反两面

胡扯,人民日报就只有正面!

我的三观,开始模糊了
返回顶部
顶部