您的位置:首页 > 编程语言 > Java开发

【GO for java programmers】面向Java开发者的GO编程3

2013-01-04 13:35 597 查看

面向Java开发者的GO编程

英文原文在此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
接口。这种类型型可满足多个接口。这是一种形式的鸭子类型。

“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
James Whitcomb Riley

匿名域

匿名域可以用于实现很像一个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
类型,所以为
MyType
e的方法也成为
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: