Go 语言学习-5

本文介绍了Go语言中的反射机制,包括反射的应用场景、变量与反射Value的转换、结构体字段与方法的访问。同时,展示了如何利用反射处理json标签以及调用结构体方法。此外,还探讨了Go的常量定义以及TCP网络编程的基础,如服务器监听、客户端连接与数据交换。最后提到了Redis的基本使用和连接池的实现。
摘要由CSDN通过智能技术生成

Go 语言学习-4

Go 反射

反射的应用场景
json tag
匿名函数 函数赋给变量 适配器函数 使用反射完成
自己创建框架

package. reflect
反射可以在运行时动态获取变量的各种信息 比如变量的类型类别
如果结构体变量 还可以获取到结构体本身的信息 包括结构体字段 方法 。
通过反射 可以修改变量的值 可以调用关联的方法
使用反射需要import (“reflect”)

反射:
变量 接口interface{} 和reflect.Value 是可以相互转换的 。
interface{} --> reflect.Value rVal:= reflect.VauleOf(b)
reflect.Value–> interface{} rVal.interface()
interface{}–> 变量。 类型断言
reflect.Value 类型和 int 等基本类型不一致 反射获得的数据不可以做算术运算 +2

func reflectTest(b interface{}) {
	rtype := reflect.TypeOf(b)
	rValue := reflect.ValueOf(b)
	r := rValue.Int() + 2
	fmt.Println(rtype, r)
	ifv:=rValue.Interface()
	num2 := ifv.(int)
	fmt.Println(num2,"num2")
}

对结构体

type Student struct {
	Name string
	Age  int
}

func reflectTestStruct(b interface{}) {
	rtype := reflect.TypeOf(b)
	rValue := reflect.ValueOf(b)
	fmt.Printf("rval=%v type=%T\n", rValue, rValue)
	ifv := rValue.Interface()
	num2 := ifv.(Student)
	fmt.Println(rtype, num2.Name)
}

反射的本质是运行时 虽然在运行时可以确定 某个值确实是该类型 但是在编译阶段无法确定 。
所以要取值需要通过断言 。

反射的注意事项 和细节说明

  1. reflect.Value.Kind 获取变量的类别 返回的是一个常量 Type 类型的具体分类
  2. Type 是类型 Kind 是类别 二者可能相同也可能不同 基本数据类型相同 结构体不同。区分一个Type 是包名+结构体名称
  3. 通过反射让变量在interface{} 和Reflect.Value 之间相互转换
  4. 使用反射获取变量的值要求类型匹配。否则会报panic
  5. 通过反射来修改变量 注意当使用Setxxx方法来设置需要通过对应的指针类型来完成 这样才能改变传入变量的值 同时需要使用到reflect.Value.Elem()
  6. reflect.Value.Elem() :
    两点需要注意:
    一是 reflect.ValueOf() 传入指针
    二是 需要Elem 修改 变量。
    反射最佳 实践-1
    1.遍历结构体字段 调用结构体方法 并获取结构体标签值
    Method Call 。
    Type 的Field 返回时StructField 可以得到结构体的标签。tag
    不能用ValueOf取得标签。
    反射调用方法 会排序 比较函数名ASCII码。
type Student struct {
	Name   string `json:"name"`
	Age    int    `json:"age"`
	Gender string
}

func testReflectJson(b interface{}) {
	typ := reflect.TypeOf(b)
	val := reflect.ValueOf(b)
	kd := val.Kind()
	if kd != reflect.Struct {
		fmt.Println("expect struct")
		return
	}
	num := val.NumField()
	fmt.Printf("num=%v\n", num)
	for i := 0; i < num; i++ {
		fmt.Printf("field %d 值为%v\n", i, val.Field(i))
		tagVal := typ.Field(i).Tag.Get("json")
		if tagVal != "" { //没有标签不显示
			fmt.Printf("field %d:tag为%v\n", i, tagVal)
		}
	}
	numMe := val.NumMethod()
	fmt.Printf("一共有%v个方法\n", numMe)
	val.Method(1).Call(nil)
	//传入的 是切片
	var params []reflect.Value
	params = append(params, reflect.ValueOf(10))
	params = append(params, reflect.ValueOf(40))
	//返回的也是切片
	res := val.Method(0).Call(params)
	fmt.Println("res=", res[0].Int())
}
func (stu Student) Print() {
	fmt.Println("--------start--------")
	fmt.Println(stu)
	fmt.Println("--------end--------")
}
func (stu Student) GetSum(nn1 int, nn2 int) int {
	return nn1 + nn2
}
func (stu Student) Set(name string, age int) {
	stu.Age = age
	stu.Name = name
}

func main() {
	//var num int = 100
	//reflectTest(num)
	var stu = Student{Name: "zhangqii", Age: 1002, Gender: "nana"}
	//reflectTestStruct(&stu)
	fmt.Println(stu)
	testReflectJson(stu)
}

反射最佳 实践-2 *******

SGG—291

常量
定义时需要初始化 const 常量定义时必须要赋值 不能修改
常量只能 是修饰bool 数值类型 int float string 类型 只能是基本数据类型 。
其他语言 常量一般要大写 但Go中没有必要要求
依然通过 首字母的大小写来控制变量的范围

const(
	a=1
	b=2)
const(
	a=itoa
	b
	c)
	// 0,1,2,

网络编程

TCP +Redis

1> Socket 编程 2> HTTP编程

网络编程基础知识
五层
应用层
传输层
网络层
链路层
物理层 网卡
tracert www.baidu,com windows 下 好多路由器不支持,故无法返回。

端口
端口分类
1-1024 固定端口
有名端口 即被某些程序固定使用 一般程序员不用
22 SSH 远程登录协议 23 telnet 使用 21 ftp 使用 25 smtp服务使用 80 iis使用
7 echo 服务
1025-65535 是动态端口 程序员可以使用。
0 是保留端口
netstat -an 查看本机有哪些端口在监听
netstat -anb 来查看监听端口的pid 再结合任务管理器关闭不安全的端口
系统要尽可能保证纯净版 有插件 会有恶意插件可能

TCP编程

服务监听
client.go

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"strings"
)

func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		fmt.Println("client dial fail", err)
		return
	}
	fmt.Println("conn success", conn)
	// 客户端发送单行数据
	//os.Stdin
	//bufio.NewReader(io.Reader(conn))
	reader := bufio.NewReader(os.Stdin)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			fmt.Println("read string err=", err)
		}
		line = strings.Trim(line, "\r\n")
		if line == "exit" {
			fmt.Println("客户端退出")
			break
		}
		// 把 \r\n 加上 可以换行。
		_, err = conn.Write([]byte(line + "\r\n"))
		if err != nil {
			fmt.Println("conn Write err=", err)
		}

	}
	//fmt.Printf("客户端发送了%d字节数据并退出", n)
}

server.go

package main

import (
	"fmt"
	"io"
	"net"
)

/**
TCP 编程 服务器监听
*/
func main() {
	fmt.Println("服务器开始监听")
	//127.0.0.1 只支持IPV4  0.0.0.0 支持IPV4 和IPV6
	listen, error := net.Listen("tcp", "0.0.0.0:8888")
	if error != nil {
		fmt.Println("listen err=", error)
	}
	defer listen.Close()
	// 循环等待客户端连接
	for {
		fmt.Println("等待客户端连接")
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("accpet err=", err)
			return
		} else {
			fmt.Println("accept success", conn.RemoteAddr().String())
		}
		//准备一个协程为客户端服务
		go process(conn)
	}
	fmt.Printf("listen=%v", listen)
}

//循环接受客户端发送的数据
func process(conn net.Conn) {
	//关闭conn
	defer conn.Close()
	for {
		buf := make([]byte, 12)
		// 1.等待 客户端通过conn 发送信息 如果 客户端没有Write 那么 就一直等待在哪里。
		fmt.Println("服务器等待客户端发送信息")
		n, err := conn.Read(buf)
		if err == io.EOF {
			//fmt.Println("服务器 read 出错", err)
			fmt.Println("客户端退出 ", err)
			return
		}
		// 3 显示客户端发送的内容到服务器的终端 注意 string(buf[:n]) 直接用buf 后面的数据不清楚。 会出现奇怪的数据
		fmt.Println(string(buf[:n]))
	}
}

经典项目 海量用户即时通讯系统

用户注册
用户登陆
显示在线的用户列表
群聊 广播
点对点聊天
离线留言 

Redis

Redis 基本介绍
Redis String 最大 512M
基本数据结构

Go 链接到Redis 。
telnet : ctrl+ ] 退出

Redis 连接池

init 函数中初始化连接池

func init() {
	pool = &redis.Pool{MaxIdle: 8, MaxActive: 0, IdleTimeout: 100, Dial: func() (redis.Conn, error) {
		return redis.Dial("tcp", "localhost:6379")
	},
	}
}

从 pool 中取出连接时 保证 连接池是开启状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值