英文原文在此www.nada.kth.se/~snilsson/go_for_java_programmers
译文同步至www.waylau.com
http://bbs.gocn.im/thread-86-1-1.html
=======================接上文========================.
Slices(切片)slice是概念上一个结构包含三个域:一个数组的指针、长度和容量。切片支持[]操作符来访问底层数组的元素。内置的len函数返回的切片长度。内置的的cap函数返回切片的能力。
给定一个数组,或另一个切片,通过a[i:j]来创建一个新的切片。这个新创建的切片指向a,从索引i开始,并结束索引j之前。它的长度是j - i。如果i 被省略,切片从0开始。如果j 被省略,切片在len(a)结束。新切片跟a一样指向相同的数组。即,改变后组成的新的切片的元素在a都能见到。新切片的容量就是简单的a减去i。数组的容量就是数组的长度。
var s []int var a [10]int s = a[:] // short for s = a[0:len(a)]
如果你创建一个值类型为[100]byte(100个字节,也许是一个缓冲区的数组),你想不复制它,而将它传递给函数,那么函数的参数声明类型[]byte,并传入数组的切片。切片也可以用make的函数创建(如下文所述)。
切片组合采用内置的append函数,Java的ArrayList提供相同的功能。
s0 := []int{1, 2}
s1 := append(s0, 3) // append a single element
s2 := append(s1, 4, 5) // append multiple elements
s3 := append(s2, s0...) // append a slice
切片语法,也可以使用在字符串上。它返回一个新字符串,其值是原始的字符串的子串
make函数Map and channel values must be allocated using the built-in function make. For example, calling map和channel值必须使用内置的函数make。例如,调用
make(map[string]int)
map[string]int返回一个新分配的值类型。相对于new, make 返回的是实际的对象,而不是一个地址。这是一致的事实,map和channel是引用类型。
对于map,make函数将容量作为一个可选的第二个参数的提示。对于channel,有一个可选的第二个参数来设置channel的缓冲能力,默认为0(无缓冲)。
make函数也可以用来分配一个切片。在这种情况下,它分配内存给基本数组并返回一个引用他的切片。该切片中的元素数是一个必需的参数。第二个可选的参数是切片的容量。
m := make([]int, 10, 20) // Same as new([20]int)[:10]方法和接口 方法
方法看起来像一个普通的函数定义,但它有一个receiver(接收者)。receiver是类似Java实例方法中的this引用。
type MyType struct { i int }
func (p *MyType) Get() int {
return p.i
}
var pm = new(MyType)
var n = pm.Get()
这声明了一个方法Get与MyType关联的。receiver被命名为p 在函数体内。
命名的类型来定义方法。如果您转换不同类型的值,新的值将有新的类型,而不是那些旧的类型。
你可以定义一个内置类型的方法,用新的命名类型声明。新的类型和内置的类型是不同的。
type MyInt int
func (p MyInt) Get() int {
return int(p) // The conversion is required.
}
func f(i int) {}
var v MyInt
v = v * v // The operators of the underlying type still apply.
f(int(v)) // int(v) has no defined methods.
f(v) // INVALID
接口
Go接口类似于Java接口,但可被视为一个实现该接口提供任何类型的在Go接口命名的方法。明确的声明是不必要的。
接口像这样:
type MyInterface interface {
Get() int
Set(i int)
}
自从 MyType 已经有了Get 方法, 我们可以让 MyType满足接口通过添加
func (p *MyType) Set(i int) {
p.i = i
}
现在任何只要将MyInterface当做参数就可以接收类型是*MyType的变量
func GetAndSet(x MyInterface) {}
func f1() {
var p MyType
GetAndSet(&p)
}
在Java术语,给*MyType 定义 Set和Get 使*MyType自动实现了MyInterface接口。这种类型型可满足多个接口。这是一种形式的鸭子类型。
匿名域可以用于实现很像一个Java子类的东西。
type MySubType struct {
MyType
j int
}
func (p *MySubType) Get() int {
p.j++
return p.MyType.Get()
}
MySubType有效实现的像是MyType的子类型.
func f2() {
var p MySubType
GetAndSet(&p)
}
Set方法是继承自MyType的,因为关联了匿名域的方法的变为了封闭类型的方法。在这种情况下,因为 MySubType有一个匿名与域 MyType类型,所以为 MyTypee的方法也成为MySubType的方法。Get方法被重写,Set方法被继承。
这是与Java中的子类不完全相同。当一个匿名域的方法被调用时,它的 receiver就是这个匿名域,而不是周围的结构体。换句话说,匿名域上的方法的不会动态调度。当你想要实现相当于Java的动态方法查找,请使用接口。
func f3() {
var v MyInterface
v = new(MyType)
v.Get() // Call the Get method for *MyType.
v = new(MySubType)
v.Get() // Call the Get method for *MySubType.
}
类型断言
使用一个类型断言可以使具有一个接口类型的变量转换成具有不同的接口类型。这是在运行时动态执行。与Java不同,并不需要任何声明两个接口之间的关系。
type Printer interface {
Print()
}
func f4(x MyInterface) {
x.(Printer).Print() // type assertion to Printer
}
转换为Printer 完全是动态的。只要x(x中存储的值的实际类型)的 动态类型 定义了一个Print方法。
===================未完待续.......==========
===================转载注明出处=============
2013-1-4