目录
指针
Go 有指针,但是没有指针运算。你不能用指针变量遍历字符串的各个字节。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
通过类型作为前缀来定义一个指针 *
。 例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
var p *int
现在 p 是一个指向整数值的指针。 变量名和 *
之间要有个空格。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
所有新定义的变量都被赋值为其类型的零值,而指针也一样。一个新定义的或者没有任何指向的指针,有值 nil
。 在其他语言中,这经常被叫做 空(NULL)指针
,在 Go 中就是 nil
。让指针指向某些内容,可以使用取址操作符 &
文章源自编程技术分享-https://mervyn.life/1d33d77f.html
- 如果一个 method 的 receiver 是
*T
,你可以在一个 T 类型的实例变量 V 上面调用这个 method,而不需要&V
去调用这个 method - 如果一个 method 的 receiver 是
T
,你可以在一个*T
类型的变量P上面调用这个 method,而不需要*P
去调用这个 method
例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
func main(){
var p *int
fmt.Printf("%v\n", p)
var i int
p = &i
fmt.Printf("%v\n", p)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
<nil>
0x18600118
例2:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
func main(){
var p *int
var i int
p = &i
*p = 8
fmt.Printf("%v\n", *p)
fmt.Printf("%v\n", i)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
8
8
因为Go没有指针运算,所以如果这样写:*p++,它表示(*p)++:首先获取指针指向的值,然后对这个值加一。
自定义类型
Go 允许定义新的类型,通过保留字 type
实现,例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
type foo int
创建了一个新的类型 foo 作用跟 int 一样。创建更加复杂的类型需要用到 struct
保留字。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
type NameAge struct {
name string //不导出
age int //不导出
}
func main(){
a := new(NameAge)
a.name = "Pete"
a.age = 42
fmt.Printf("%v\n", a)
fmt.Printf("%v\n", a.name)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
&{Pete 42}
Pete
struct 声明
注意 struct{}
中首字母大写的字段可以被导出, 也就是说,在其他包中可以进行读写。 字段名以小写字幕开头是当前包的私有的。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
例2:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
type person struct {
name string
age int
}
var P person // P现在就是person类型的变量了
P.name = "Astaxie" // 赋值"Astaxie"给P的name属性.
P.age = 25 // 赋值"25"给变量P的age属性
fmt.Printf("The person's name is %s", P.name) // 访问P的name属性.
除了上面这种P的声明使用之外,还有几种声明使用方式文章源自编程技术分享-https://mervyn.life/1d33d77f.html
-
按照顺序提供初始化值文章源自编程技术分享-https://mervyn.life/1d33d77f.html
P := person{"Tom", 25}
-
通过
field:value
的方式初始化,这样可以任意顺序(以这种方式初始化的时候每个字段都要写出来)文章源自编程技术分享-https://mervyn.life/1d33d77f.htmlP := person{age:24, name:"Tom"}
-
通过
new
函数分配一个指针,此处 P 的类型为*person
文章源自编程技术分享-https://mervyn.life/1d33d77f.htmlp := new(person)
例3:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
// 声明一个新的类型
type person struct {
name string
age int
}
// 比较两个人的年龄,返回年龄大的那个人,并且返回年龄差
// 注意:struct也是传值的
func Older(p1, p2 person) (person, int) {
if p1.age>p2.age { // 比较p1和p2这两个人的年龄
return p1, p1.age-p2.age
}
return p2, p2.age-p1.age
}
func main() {
var tom person
// 赋值初始化
tom.name, tom.age = "Tom", 18
// 两个字段都写清楚的初始化
bob := person{age:25, name:"Bob"}
// 按照struct定义顺序初始化值
paul := person{"Paul", 43}
tb_Older, tb_diff := Older(tom, bob)
tp_Older, tp_diff := Older(tom, paul)
bp_Older, bp_diff := Older(bob, paul)
fmt.Printf("Of %s and %s, %s is older by %d years\n",
tom.name, bob.name, tb_Older.name, tb_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n",
tom.name, paul.name, tp_Older.name, tp_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n",
bob.name, paul.name, bp_Older.name, bp_diff)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
Of Tom and Bob, Bob is older by 7 years
Of Tom and Paul, Paul is older by 25 years
Of Bob and Paul, Paul is older by 18 years
struct 的匿名字段
我们上面介绍了如何定义一个 struct
,定义的时候是字段名与其类型一一对应, 实际上 Go 支持只提供类型, 而不写字段名的方式,也就是匿名字段
,也称为嵌入字段
。当匿名字段是一个 struct 的时候,那么这个 struct 所拥有的全部字段都被隐式地引入了当前定义的这个 struct。
例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // 匿名字段,那么默认Student就包含了Human的所有字段
speciality string
}
func main() {
// 我们初始化一个学生
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
// 我们访问相应的字段
fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight)
fmt.Println("His speciality is ", mark.speciality)
// 修改对应的备注信息
mark.speciality = "AI"
fmt.Println("Mark changed his speciality")
fmt.Println("His speciality is ", mark.speciality)
// 修改他的年龄信息
fmt.Println("Mark become old")
mark.age = 46
fmt.Println("His age is", mark.age)
// 修改他的体重信息
fmt.Println("Mark is not an athlet anymore")
mark.weight += 60
fmt.Println("His weight is", mark.weight)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
His name is Mark
His age is 25
His weight is 120
His speciality is Computer Science
Mark changed his speciality
His speciality is AI
Mark become old
His age is 46
Mark is not an athlet anymore
His weight is 180
方法
可以对新定义的类型创先函数以便操作,可以通过两种途径:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
- 创建一个函数接受这个类型的参数。
func doSomething(in1 *NameAge, in2 int) { /* ... */ }
你可能已经猜到了,这其实就是函数调用。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
- 创建一个工作在这个类型上的函数:
func (in1 *NameAge) doSomething(in2 int) { /* ... */ }
这是方法调用,可以类似这样使用:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
var n *NameAge n.doSomething(2)
例1:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
type NameAge struct {
name string
age int
}
func main(){
a := new(NameAge)
a.name = "Pete"
a.age = 42
doSomething(a, 3)
}
func doSomething(in1 *NameAge, in2 int){
fmt.Printf("%v\n", in1.name)
fmt.Printf("%d\n", in2)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
Pete
3
例2:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
type NameAge struct {
name string
age int
}
func main(){
a := new(NameAge)
a.name = "Pete"
a.age = 42
a.doSomething(333)
}
func (in1 *NameAge) doSomething(in2 int){
fmt.Printf("%v\n", in1.name)
fmt.Printf("%d\n", in2)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
Pete
333
类型转换
有时需要将一个类型转换为另一个类型。在 Go 中可以做到,不过有一些规则。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
注意 Go 的字符串是 UTF-8
编码的,一些字符可能是 1、2、3 或者 4 个字节结尾。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
func main(){
mystring := "hello world"
byteslice := []byte(mystring)
for _, val := range byteslice {
fmt.Printf("%v\n", val)
}
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
104
101
108
108
111
32
119
111
114
108
100
例2文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
func main(){
mystring := "hello world"
byteslice := []rune(mystring)
for _, val := range byteslice {
fmt.Printf("%c\n", val)
}
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
h
e
l
l
o
w
o
r
l
d
对于数值,定义了下面的转换:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
- 将整数转换到指定的(bit)长度:uint8(int);
- 从浮点数到整数:int(float32)。这会截断浮点数的小数部分;
- 其他的类似:float32(int)。
例:文章源自编程技术分享-https://mervyn.life/1d33d77f.htmlpackage main import "fmt" func main(){ myfloat := 123.72 myint := int(myfloat) fmt.Printf("%.3f\n", myfloat) fmt.Printf("%d\n", myint) }
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
123.720 123
用户定义类型的转换文章源自编程技术分享-https://mervyn.life/1d33d77f.html
如何在自定义类型之间进行转换?这里创建了两个类型 foo 和 bar ,而 bar 是 foo 的一个别名:
例:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
package main
import "fmt"
type foo struct { int } //匿名字段
type bar foo
func main(){
b := bar{1} //声明b 为bar 类型,并赋初值
var f foo = b
//上面赋值b 到f,这会引起一行错误cannot use b (type bar) as type foo in assignment(不能使用b(类型bar)作为类型foo 赋值)
var f foo = foo(b) //这个是可以的
fmt.Printf("%d\n", f)
}
输出结果:文章源自编程技术分享-https://mervyn.life/1d33d77f.html
{1}
注意:转换 b 到 int 同样会出错;整数与有整数字段的结构并不一样。文章源自编程技术分享-https://mervyn.life/1d33d77f.html
评论