今日学习内容
1Go语言中的结构(struct)与方法(method)
结构体是复合类型,当需要定义一个类型,它由一系列属性组成,每个属性都有自己的类型和值的时候,就应该使用结构体,它把数据聚集在一起。
1.1结构体定义
type identifier struct {
field1 type1
field2 type2
}
使用 new 函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:var t *T = new(T)
package main
import "fmt"
type struct1 struct {
i1 int
f1 float32
str string
}
func main() {
ms := new(struct1)
ms.i1 = 10
ms.f1 = 15.5
ms.str= "Chris"
fmt.Printf("The int is: %d
", ms.i1)
fmt.Printf("The float is: %f
", ms.f1)
fmt.Printf("The string is: %s
", ms.str)
fmt.Println(ms)
}
还可以采用的初始化方式为ms:=&struct1{10,3.3,"test"}
1.2使用自定义包中的结构体
目录结构如下
package structPack
type ExpStruct struct {
Mi1 int
Mf1 float32
}
package main
import(
"./structPack"
"fmt"
)
func main() {
struct1 := new(structPack.ExpStruct)
struct1.Mi1=0
struct1.Mf1=16.3
fmt.Printf("Mi1 = %d
", struct1.Mi1)
fmt.Printf("Mf1 = %f
", struct1.Mf1)
}
1.3带标签的结构体:结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记,标签的内容不可以在一般的编程中使用,只有包 reflect
能获取它,在一个变量上调用 reflect.TypeOf()
可以获取变量的正确类型,如果变量是一个结构体类型,就可以通过 Field 来索引结构体的字段,然后就可以使用 Tag 属性。
package main
import(
"fmt"
"reflect"
)
type TagType struct {
field1 bool "An important answer"
field2 string "The name of the thing"
field3 int "How much there are"
}
func main() {
tt:=TagType{(true),"Barak obama",1}
for i:=0;i<3;i++{
refTag(tt,i)
}
}
func refTag(tt TagType, ix int){
ttType:=reflect.TypeOf(tt)
ixField:=ttType.Field(ix)
fmt.Printf("%v
", ixField.Tag)
}
1.4匿名字段与内嵌结构体:结构体可以包含一个或多个 匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型就是字段的名字。匿名字段本身可以是一个结构体类型,即 结构体可以包含内嵌结构体
package main
import "fmt"
type A struct {
ax,ay int
}
type B struct {
A
bx, by int
}
func main() {
b:=B{A{1,2},3.0,4.0}
fmt.Println(b.ax, b.ay, b.bx, b.by)
fmt.Print(b.A)
}
1.4方法:格式为func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }
package main
import "fmt"
type TwoInts struct {
a int
b int
}
func main() {
two1:=new(TwoInts)
two1.a = 12
two1.b = 10
fmt.Printf("The sum is: %d
", two1.AddThem())
fmt.Printf("Add them to the param: %d
", two1.AddToParam(20))
two2 := TwoInts{3, 4}
fmt.Printf("The sum is: %d
", two2.AddThem())
}
func (tn *TwoInts) AddThem() int{
return tn.a+tn.b
}
func (tn *TwoInts) AddToParam(parm int) int{
return tn.a+tn.b+parm
}
1.4.1函数和方法的区别:函数将变量作为参数:Function1(recv),方法在变量上被调用:recv.Method1()
1.4.2多重继承:多重继承指的是类型获得多个父类型行为的能力,它在传统的面向对象语言中通常是不被实现的。因为在类继承层次中,多重继承会给编译器引入额外的复杂度。但是在 Go 语言中,通过在类型中嵌入所有必要的父类型,可以很简单的实现多重继承。
package main
import (
"fmt"
)
type Camera struct{}
func (c *Camera) TakeAPicture() string{
return "click"
}
type Phone struct{}
func (p *Phone) Call() string{
return "Ring Ring"
}
type CameraPhone struct {
Camera
Phone
}
func main() {
cp := new(CameraPhone)
fmt.Println("Our new CameraPhone exhibits multiple behaviors...")
fmt.Println("It exhibits behavior of a Camera: ", cp.TakeAPicture())
fmt.Println("It works like a Phone too: ", cp.Call())
}
UDP ping程序:
使用Python编写一个客户ping程序,该客户发送一个简单的Ping报文,接收一个从服务器返回的报文,并确定客户发送ping报文到接收报文为止的时延。
服务器端代码UDPPingServer.py
from socket import *
import random
#创建一个UDP套接字
serverSocket=socket(AF_INET,SOCK_DGRAM)
#绑定IP地址和端口号
serverSocket.bind(('',12000))
while True:
#随机生成1-10数字
rand=random.randint(0,10)
#接收来自客户端的IP地址和数据包
message,address=serverSocket.recvfrom(1024)
message=message.upper()
#如果数字小于4 考虑丢弃
if rand < 4:
continue
#否则服务端响应
serverSocket.sendto(message,address)
客户端代码UDPPinger.py
from socket import*
import time
#服务器地址
serverName='45.78.44.224'
#服务器端口
serverPort =12000
#创建UDP套接字
clientSocket=socket(AF_INET,SOCK_DGRAM)
#设置超时时间
clientSocket.settimeout(1)
for i in range(0,10):
sendTime =time.time()
# 生成数据报,编码为bytes以便发送
message=('Ping %d %s' % (i+1,sendTime)).encode()
try:
#将消息发送到服务器
clientSocket.sendto(message,(serverName,serverPort))
# 从服务器接收信息,同时也能得到服务器地址
modifiedMessage,serverAddress=clientSocket.recvfrom(1024)
#计算往返时间
rtt=time.time()-sendTime
# 显示信息
print('Sequence %d: Reply from %s RTT = %.3fs' % (i + 1, serverName, rtt))
except Exception as e:
print('Sequence %d: Request timed out' % (i + 1))
#关闭套接字
clientSocket.close()
效果如下