本文属翻译文章
首发于 http://goroot.org
- 概念不同点
- 语法
- 常量
- 片(Slices)
- 建值(Making values)
- 接口
- 并发
- 通道
GO是一个以通用系统语言为设计目标的系统级语言, 如 C++. 以下是针对C++程序员的一些学习拉摘要. 这文章主要讨论GO和C++的不同。
对于更一般的介绍,请另参网站其它文章:
概念不同
* GO没有带构建器和析构器的类. 取而代之的是继承阶级和虚函数, GO提供接口,下文会详细说明. C++用模板实现
* Go使用内存回收机制.没有必要也不可能明确地回收内存. 现代处理器中内存回收是为了更高效地编程
* GO有指针但没有指针运算. 你不能用指针变量来遍历一个字符的各个位
* GO中数组是优先值. 当数组作为参数使用,函数获得数组的一个拷贝, 而不是指针. 然而在实际应用中一般用片作为参数;片有指向数组的指针;片在下面会详细讨论。
* 字符串由语言提供,一旦建立就不能再改变.
* GO提供哈希表,称之类映射(map)
* 分离的线程执行, 通过通道通讯,也是语言本身集成的.后面会详细讨论.
* 特定类型 (映射和通道后面会详细说明) 以引用方式传递, 而非值传递. 传递一个映射给函数不会获得函数的一个拷贝, 所以如果函数改变了其值,调用者能看得到. 在C++中可以理解成引用.
*GO没有头文件.取而代之地把所有文件当成包的一部分. 当包定义了一个以大写开头的对象 (类型、常量、变量、函数),这个对象在所有引用该包的文件中可见
* Go 不支持隐含类型转换. 不同类型数据进行运算时需要转换
* Go 不支持函数重载和用户自定义操作符.
* Go does 常量或可变限定词
* Go 使用nil而不是C++中的NULL或0作为逻辑非。
句法
声明句法和C++相比相反. 类型写在变量前. 这样声明更容易看清楚
Go C++
var v1 int; // int v1;
var v2 string; // const std::string v2; (approximately)
var v3 [10]int; // int v3[10];
var v4 []int; // int* v4; (approximately)
var v5 struct { f int }; // struct { int f; } v5;
var v6 *int; // int* v6; (but no pointer arithmetic)
var v7 map[string]int; // unordered_map<string, int>* v7; (approximately)
var v8 func(a int) int; // int (*v8)(int a);
声明通常由关键词前导,然后是名称。关键词为 var, func, const, type之一. 方法声明是很少的例外。
你也可以使用关键词加括号来作一系列的声明。
var (
i int;
m float
)
当声明一个函数, 要么为每个参数提供一个名称,要么提供一个名称给任意参数;但不能忽略一部分而只提供一半分参数,你可以把相关类型的参数组织到一起:
func f(i, j, k int, s, t string);
声明时允许初始化. 如果这样做,那么指定类型是允许的,但不是必要的. 如果声明时变量类型没有被指定,那么其类型由初始化的值决定.
var v = *p;
请再参见关于常量的讨论. 如果一个变量没有被明确地初始化, 那么必须声明其类型. 在这种情况下会被隐式初始化为零值(0, nil, 或其它.). 所以Go中没有未被初始化的变量.
函数中,短声明语法可用:= .
v1 := v2;
这等价于
var v1 = v2;
Go 多值平行赋值.
i, j = j, i; // 交换i j的值.
函数能返回多值, 由括号内的列表表示. 返回值可同时赋值给多个值.
unc f() (i int, j int);
v1, v2 = f();
Go 把分号作为分隔符, 而不是终止标志. 而且, 分号可以被省略如果后面紧跟一个声明块的闭括号或者不是表达式一部分的花括号(如, var s struct {} or { x++ }). 分号在高层的文件中不需要使用(全局声明中). 然而,在语句中他们始终被允许的,所以你依然可以按照C++的规范来写.
当使用指针指向结构体要用 . 而不是 ->. 所以语法上来说一个结构体跟一个指针指向结构体是相同的处理方式.
type myStruct struct { i int }
var v9 myStruct; // v9 has structure type
var p9 *myStruct; // p9 is a pointer to a structure
f(v9.i, p9.i)
Go在if语句中不要求括号把条件括起来, for语句的条件式也不要,或者switch语句. 但后面的语句需要用花括号.
if a < b { f() } // Valid
if (a < b) { f() } // Valid (condition is a parenthesized expression)
if (a < b) f(); // INVALID
for i = 0; i < 10; i++ {} // Valid
for (i = 0; i < 10; i++) {} // INVALID
Go 没有while和do..while语句. for语句可以使用单条件来实现while语句的功能. 忽略终止条件就能实现无休止循环。
Go 允许break和continue指定特定的层次. 但指定的必需是for,if,switch.
在一个switch语句中,case标签不能跳过. 你可以使用fallthrough来跳过. 这适用于相临的语句。
switch i {
case 0: // empty case body
case 1:
f() // f is not called when i == 0!
}
但一个case可以有多个值.
switch i {
case 0, 1:
f() // f is called if i == 0 || i == 1.
}
case中的值不需要是常量,或者是偶数; 任何能进行等值比较的类型,如字符串和指针都可以,如果case的值被省略,则默认为真。
switch {
case i < 0:
f1()
case i == 0:
f2()
case i > 0:
f3()
}
++ --操作符只能用在语句中,不能用在表达式中. 不能写 c = *p++. 而*p++ 会被解释为 (*p)++.
defer语句用来调用一个函数,当一个函数包含了defer语句的返回值.
fd := open("filename");
defer close(fd); // fd will be closed when this function returns.
常量 [Top]
Go中的常量可以不指定类型. 这同样可以应用到用 const 声明的常量上, 如果声明时没有指定类型,并且在初始化时使用不指定类型的赋值. 一个常量会被自动添加上类型当它进行某种要求特定类型运算时. 这允许常量相对自由地使用而无需明确地进行类型转换.
var a uint;
f(a + 1) // untyped numeric constant "1" becomes typed as uint
语言不限制未指定类型的数字常量或常量表达式的大小. 只有当常量被应用在某种要求特定类型的数据操作时,常量的大小才会被限定.
const huge = 1 << 100;
f(huge >> 98)
Go 不支持枚举. 但是相应地,你可以使用在一个单常量声明中使用iota来获得一系列递增的值. 当一个常量的初始化表达化被省略了,它会重用前面的表达式.
const (
red = iota; // red == 0
blue; // blue == 1
green // green == 2
)
片[Top]
片在概念上是具有三个域的结构: 指向数组的指针, 长度, 容量. 片支持使用 [] 操作符来获得指向数组的元素. 内建len 函数返回片的长度. 内建cap函数返回容量.
给定一个数组,或者另一个片,一个片通过a[I:J]来创建. 这样创建了一个指向a的片引用,开始于索引I,终止于索引J之前. 长度为J-I.新片指向与a相同的数组.也就是说,改变新片的内容在a数组也可见 . 新片的容量等于a的容量减去I. 数组的容量是数组的长度. 你也可以赋一个数组指针给一个片; 给定 var s []int; var a[10] int, 赋值 s = &a 等同于 s = a[0:len(a)].
。。。。翻译中,未完待续。。。。