面向Java开发者的GO编程
英文原文在此www.nada.kth.se/~snilsson/go_for_java_programmers
译文同步至http://blog.csdn.net/kkkloveyou/article/details/8256649
http://bbs.gocn.im/thread-52-1-1.html
=======================以下正文========================.
本文旨在帮助JAVA开发者迅速掌握Go语言.
开始用一个很容易能被所有的Java程序员认出的例子来突出特色,然后对GO的框架给出了详细的的描述,最后用一个例子来说明GO结构中没有与Java直接对应处。
Hello stack (一个栈的例子)
为了吊起你的胃口,我们用一个麻雀虽小,五脏俱全和符合习惯的例子对应这个Stack.java程序
// 包collection实现了生成栈. package collection // 零值栈是一个空栈,准备被使用. type Stack struct { data []interface{} } // Push函数将x添加到栈顶. func (s *Stack) Push(x interface{}) { s.data = append(s.data, x) } // Pop函数是将栈顶元素移除并返回. // 在Pop函数执行在空栈时,会被一个运行时的error警示. func (s *Stack) Pop() interface{} { i := len(s.data) - 1 res := s.data[i] s.data[i] = nil // 避免内存泄露 s.data = s.data[:i] return res } // Size函数返回栈中元素的个数 func (s *Stack) Size() int { return len(s.data) }
- 顶级声明出现之前,直接的评论是文档注释。他们是纯文字。.
- 对于声明,你把名字写在类型后面.
-
struct
对应Java中的类, 但struct组成不是方法而只能是变量. -
T
interface{}
类型对应Java的Object
. 在GO中它被所有的类型所实现,而不仅仅是引用类型. -
代码段
(s*Stack)
声明了一个方法,接收者s
对应Java中的this
. -
操作符
:=
声明并初始化了一个变量. 它的类型可以从初始化表达式中推导出.
这里是一个的Hello world程序,演示了如何使用collection.Stack
的抽象数据类型.
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() //输出: hello, world }
概念上的差异
- Go的构造器没有类。Go 用structs和interfaces来替代实例化方法,类的继承机制,动态方法查找.也可用于Java使用泛型接口
-
Go提供所有类型的指针的值,而不只是对象和数组。对于任何类型
T
,有一个相应的指针类型*T
表示指针指向类型T
的值。 -
Go允许任何类型都有方法而没有装箱的限制 方法receiver,在Java中对应
this
可以是直接值或者是指针. - 数组在Go就是值. 当一个数组被当做函数的参数时,这个函数接收到的是数组的拷贝而不是它的指针. 然而在实践中,函数经常使用slices作为参数; slices引用了基础数组.
- 该语言提供了字符串,一个字符串行为就像一个字节片,但是是不可改变的。
- 该语言中的哈希表被称作maps.
- 该语言提供了独立运行的线程goroutines和他们之间的通信渠道channels.
- 某些类型(maps, slices, 和 channels)是按引用传递,而不是值。也就是说,传递一个map到函数并而不是拷贝map,如果函数修改了map,将被调用者看到变化。在Java术语来说,可以认为这是一个map的引用.
- Go提供了两种访问级别对应Java的public和包的private.如果它的命名是大写字母开头就是最高级别public,反之就是包的private.
- 作为替换Java中的异常机制, Go采用了类型error值来表示事件,如文件结尾,和运行时的panics来表示运行时的错误,如数组越界等.
- Go不支持隐式类型转换。混合使用不同类型的操作需要显式转换.
- Go不支持函数重载。在同一范围内的函数和方法必须具有唯一的名称.
-
Go使用
nil
表示无效的指针,类似于Java使用null
.
句法
声明
声明是跟Java是相反的。你在类型后面再写名称,类型声明从左往右更容易读
Go 与Java相对应的
var v1 int
|
int v1;
|
var v2 *int
|
Integer v2;
|
var v3 string
|
String v3 = "";
|
var v4 [10]int
|
int[] v4 = new int[10]; // v4 在Go中是一个值.
|
var v5 []int
|
int[] v5;
|
var v6 *struct { a int }
|
C v6; // Given: class C { int a; }
|
var v7 map[string]int
|
HashMap<String,Integer> v7;
|
var v8 func(a int) int
|
F v8; // Given: interface F { int f(int a); }
|
声明的一般形式是一个关键字后面跟着被声明对象的名字.这个关键字是const
,type
,var
,
或者func
. 您也可以使用一个关键字,后面的括号中跟着一系列声明.
var ( n int x float64 )
当声明一个函数,你必须提供每个参数的名称,或者不提供任何参数的名称,你不能提供了一些而忽略了另外一些名字。 您可以组合几个相同类型的名称:
func f(i, j, k int, s, t string)
一个变量可以在声明时初始化。当这样做时,指定的变量的类型是允许的,但不是必需的。当未指定类型,默认的是初始化表达式的类型.
var v9 = *v2
如果一个变量没有立即初始化,必须要制定类型。那样的情况下,它它会被隐式初始化该类型的零值zero value(0
,nil
,""
,
等.). Go不存在未初始化的变量.
短声明
在函数中,一个短的声明句法是:=
表示.
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
多重分配
GO允许多重分配。在右边的表达式会在评估后,再分配到任何的左操作数。
i, j = j, i //交换i和j.
函数可以具有多个返回值,表示由括号中的列表。返回的值可以存储分配给一个变量列表。
func f() (i int, pj *int) { ... } v1, v2 = f()
空白标识符
空白标识符提供了一种忽略多值表达式返回值的方式,用下划线字符表示: The blank identifier, represented by the underscore character, provides a way to ignore values returned by a multi-valued expression:
v1, _ = f() // 忽略f()返回的第二个值.
分号和格式
为了消除对分号和格式不必要的担忧,你可能会用gofmt
程序来写GO风格的标准代码, 虽然这种风格看起来很古怪,但熟悉了之后最终会像其他语言风格一样变得舒服
Go的代码在实际中很多出现分号。严格来说,Go所有的声明都用分号结束。但是Go毫无疑问会在每个非空白行的结尾插入一个分号,除非它还没有完. 这样做的后果是,在某些情况下,Go不允许断行。 举例,你可能会像下面这样写:
func g() { //无效的;“{”应该是在前面那一行。 }
在g()
后面会被插入一个分号,这样就使他像是一个函数声明而不是函数定义了 类似的,你不能这样写:
if n == 0 { } else { // 无效的; "else {" 应该是在前面那一行。 }
在}
后和else
前面会插入一个分号,导致句法错误.
===================未完待续.......==========
===================转载注明出处=============
2012-12-4
有疑问加站长微信联系(非本文作者)