Go语言基础(一)之函数调用、传参、反射机制、类型断言与转换

2023-11-12

Go语言基础(一)之函数调用、传参、反射机制

1.1 函数调用

package main
func myFunction(a,b int)(int,int){
	return a+b,a-b
	}
func main(){
	myFunction(66,77)
	}

使用编译命令go tool compile -SNl main.go ,得到汇编指令,根据此汇编指令分析调用myFunction之前的栈情况:

  • 第一步,main函数通过SUBQ $40,sp 指令一共在栈上分配了40bytes的内存空间,并先压入栈基址指针。从栈顶到栈底空间代号为SP~SP16(16个字节,保存myFunction函数的俩参数)、SP16~SP32(16个字节,保存myFunction函数的俩返回值)、SP32~basepointer(8个字节,保存main函数的栈基址指针)
  • 第二步,压入参数。myFunction函数的压参顺序:从右到左,此处即77位于SP8~SP16,66位于SP~SP8
  • 第三步,调用函数myFunction。对应的汇编指令为CALL “”.myFunction
  • 第四步,执行myFunction的汇编指令。首先会初始化返回地址并压入栈中,此时它为栈顶SP0~SP8,然后移动SP指针获取相对的参数地址(也就是之前的SP0~SP16,现在是SP8~SP24)执行业务操作,最终将返回值栈的指定地址空间即之前的SP16~SP32,现在的SP24~SP36.剩余的4个字节依然是basepointer。

总结:go使用栈来调用或传递参数及保存返回值,所以只需根据实际情况在栈上多申请内存就可以返回多个值

与C的区别:

C使用寄存器和栈来传递参数,特点在于:

  • cpu访问栈的开销比寄存器大多了,所以相比go减少了很多开销
  • 需单独处理参数过多的情况,增加了复杂度

GO使用栈来传递参数,特点在于:

  • 不需考虑不同架构上的寄存器差异
  • 不需考虑超过寄存器数量的参数如何处理
  • 函数入参和出参的空间由栈来分配

1.2 参数传递

关键问题:传值还是传引用
区别:影响的是当我们在函数中对参数进行修改时会不会影响调用方看到的数据。
传值:调用时会对参数进行拷贝,调用方和被调用方持有两份不同的数据。
传引用:调用时会传递参数的指针,此时两方持有相同的数据,修改一方,另一方也会随之修改。
不同语言会由不同的传递方式,go选择了默认传值,当然也可以传引用/指针。

1.2.1 整型和数组

package main
func myFunction(i int ,arr [2]int){
	fmt.Printf("in myFunction -i=(%d,%p) arr=(%v,%p)\n",i,&i,arr,&arr)
	}
func main(){
	i:=30
	arr:=[2]int{66,77}
	fmt.Printf("before call -i=(%d,%p) arr=(%v,%p)\n",i,&i,arr,&arr)
	myFunction(i,arr)
	fmt.Printf("after call -i=(%d,%p) arr=(%v,%p)\n",i,&i,arr,&arr)	

$ go run main.go
before call -i=(30,0xc00009a000) arr=([66,77],0xc00009a010)
in myFunction -i=(30,0xc00009a008) arr=([66,77],0xc00009a020)
after call -i=(30,0xc00009a000) arr=([66,77],0xc00009a010)

可以看出main函数中i和arr的地址和myFunction函数中i和arr的地址不同,说明是参数是传值的方式。
若在myFunction中修改参数值:`

package main
func myFunction(i int ,arr [2]int){
	i:=29
	arr[1]=88
	fmt.Printf("in myFunction -i=(%d,%p) arr=(%v,%p)\n",i,&i,arr,&arr)
	}
func main(){
	i:=30
	arr:=[2]int{66,77}
	fmt.Printf("before call -i=(%d,%p) arr=(%v,%p)\n",i,&i,arr,&arr)
	myFunction(i,arr)
	fmt.Printf("after call -i=(%d,%p) arr=(%v,%p)\n",i,&i,arr,&arr)	

$ go run main.go
before call -i=(30,0xc00009a000) arr=([66,77],0xc00009a010)
in myFunction -i=(29,0xc00009a028) arr=([66,88],0xc00009a040)
after call -i=(30,0xc00009a000) arr=([66,77],0xc00009a010)

myFunction和main中的参数值和地址依然没有关系,所以整型和数组的传参方式为传值,是值的拷贝

1.2.2 结构体和指针

package main
type Mystruct struct{
	i int
	}
func myFunction(a Mystruct,b *Mystruct){
	a.i=31
	b.i=41
	fmt.Printf("in myFunction -a=(%d,%p) -b=(%d,%p)\n",a,&a,b,&b)
	}
func main(){
	a:=Mystruct{i:30}
	b:=&Mystruct{i:40}
	fmt.Printf("before call -a=(%d,%p) -b=(%d,%p)\n",a,&a,b,&b)
	myFunction(a,b)
	fmt.Printf("after call -a=(%d,%p) -b=(%d,%p)\n",a,&a,b,&b)	
	}

$ go run main.go
before call -i=(30,0xc000018178) arr=(&{40},0xc00000c028)
in myFunction -i=(31,0xc000018198) arr=(&{41},0xc00000c038)
after call -i=(30,0xc000018178) arr=(&{41},0xc00000c028)

可以得出以下结论:

  • 传递结构体时,传递的是值,会对值进行拷贝
  • 传递结构体指针时,传递的是指针,仅对指针进行拷贝
    b.i可以看作是(*b).i,即先获取指针b背后的结构体,再修改结构体的成员变量,下面分析go语言结构体在内存中的布局:
type Mystruct struct{
	i int
	j int
	}
func myFunction(ms *Mystruct){
	ptr:=unsafe.Pointer(ms)#位于栈顶的基地址
	for i:=0;i<2;i++{
		c:=(*int)(unsafe.Pointer((uintptr(ptr)+uintptr(8*i))))#每次循环,基地址移动8个字节访问下个成员
		*c+=i+1
		fmt.Printf("[%p] %d\n",c,*c)
		}
	}
func main(){
	a:=&Mystruct{i:40,j:50}
	myFunction(a)#传参传入的是指针,因此下面的printf地址不变
	fmt.Printf("[%p] %v\n",a,*a)
	}

$ go run main.go
[0xc000018180] 41
[0xc000018188] 52
[0xc000018180] &{41,52}

通过指针的方式修改结构体中的成员变量,结构体在内存中是一片连续空间,指向结构体的指针也是指向结构体的首地址,将Mystruct指针修改成int类型,访问新指针就会返回整型i。
所以go中,将指针作为参数时,会对指针进行复制,此时两个指针都指向同一片内存空间。所以在传递数组或内存很大的结构体时,尽量使用指针作为参数来传递 ,防止大量数据拷贝影响性能。

1.2.3 接口

一组方法的签名或集合。
作用:通过接口与具体实现分离,解除上下游的耦合,上层模块不再需要依赖下层模块,只需依赖好一个具体的接口。

隐式接口

type error interface{
	Error() string
	}
type RPCerror struct{
	code int64
	message string
	}
func (e *RPCerror) Error() string{
	return fmt.Sprintf(e.message,e.code)
	}
  • 在Java中,实现接口需要显式的声明接口并实现所有方法
  • 在go中,只要实现了接口中的所有方法就隐式的实现了接口
  • 此处可以看出RPCerror结构体实现了error接口,但是使用的时候并不关心它实现了哪些接口,只有在传递参数、返回参数以及变量赋值时才会进行类型检查。
func main(){
	var rpcErr error=NewRPCerror(400,'unknown error')//变量赋值,类型检查
	err:=AsErr(rpcErr)//类型检查,传递参数
	println(err)
	}
func NewRPCerror(code int64,msg string) error {
	return &RPCerror{//类型检查,返回参数
		code:code
		message:msg}}
func AsErr(err error) error {
	return err
	}

结构体(指针)与接口(重要,易混)

同时使用接口和指针存在的困惑的问题

type cat struct{}
type Duck interface{
	Quack()
	}
func (c cat) Quack {}//结构体实现接口
func (c *cat) Quack {}//结构体指针实现接口
var d Duck = cat{}//结构体初始化接口
var d Duck = &cat{}//结构体指针初始化接口

实现接口和初始化接口与结构体和结构体指针组成了以下四种情况,并不都能通过编译

编译结果 结构体实现接口 结构体指针实现接口
结构体初始化变量 通过 不通过
结构体指针初始化变量 通过 通过
//结构体实现接口,结构体(指针)初始化变量
type cat struct{}
func (c cat) Quack() {
	fmt.Println('ff'}
	}
func main(){
	var c Duck = cat{}/&cat{}//结构体指针可以隐式的获取唯一指向的结构体
	c.Quack()
	}
//结构体指针实现接口,结构体初始化变量
type cat struct{}
func (c *cat) Quack() {
	fmt.Println('ff'}
	}
func main(){
	var c Duck = cat{}//编译报错,新建了一个全新cat类型,cat类型没有实现Duck接口,之前实现Duck接口的是指向之前的cat类型的指针
	c.Quack()
	}

附:书中第132页还对这几个指针和结构体的类型转换的底层汇编作了分析理解

注意:接口是不同于结构体、数组等数据结构的单独的数据结构
例如:

type TestStruct struct{}

func NilorNot(v interface{}) bool{
	return v==nil
	}
func main(){
	var s *TestStruct
	fmt.Println(s==nil)//True
	fmt.Println(NilorNot(s))//False
	}

NilorNot(s)返回为False的原因是参数的传递与赋值发生了类型的隐式转换,*TestStruct此结构体指针类型转换成了interface{}类型,转换后的变量包含了转换前的变量和类型信息。

1.3 反射机制

反射就是程序在运行时能够 “观察” 并且修改自己的行为,主要依赖reflect包实现简化代码逻辑。
包中主要有两个函数和两个类型:

  • 函数:reflect.TypeOf获取入参的类型信息,reflect.ValueOf获取数据运行时的值
  • 类型:Type,一个接口,包含methodbyname、implements等方法;Value,一个结构体,没有对外暴露的字段,提供了获取或者写入数据的方法。

反射包中所有方法都是围绕着Type和Value这两个反射对象设计的。反射中涉及到三种数据类型:go语言基本类型(int,string,float等)、空接口类型(interface{})、反射对象(使用了reflect包后得到的对象的统称,如reflect.TypeOf(author)、reflect.ValueOf(author)都是反射对象)

一个例子引入

func main() {
 rv := []interface{}{"hi", 42, func() {}}
 for _, v := range rv {
  switch v := reflect.ValueOf(v); v.Kind() {
  case reflect.String:
   fmt.Println(v.String())
  case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   fmt.Println(v.Int())
  default:
   fmt.Printf("unhandled kind %s", v.Kind())
  }
 }
}
-----output----
hi
42
unhandled kind func

在程序中主要是声明了 rv 变量,变量类型为 interface{},其包含 3 个不同类型的值,分别是字符串、数字、闭包。
而在使用 interface{} 时常见于不知道入参者具体的基本类型是什么,那么我们就会用 interface{} 类型来做一个伪 “泛型”
此时又会引出一个新的问题,既然入参是 interface{},那么出参时呢?
func F(interface{}) interface{},出参类型interface{}是int还是string还是其他,因此必然离不开类型的判断,这时候就要用到反射,也就是 reflect 标准库。反射过后又再进行 (type) 的类型断言。

1.3.1 三大法则

1.从interface{}变量可以反射出反射对象。

func main(){
	author:='drave'
	fmt.Println(reflect.TypeOf(author))//string
	fmt.Println(reflect.ValueOf(author))//drave
	}

TypeOf和ValueOf是链接go语言类型到反射类型转换的桥梁,虽然这里看着author是string类型,但是这俩函数TypeOf和ValueOf的入参为interface{}类型,中间发生了string到interface{}的类型转换,获取了反射对象后(Type和Value这两种)就可以使用反射包里的方法了
2.从反射对象可以还原回interface{}变量

func main(){
	author:='drave'
	//经历了基本类型-》空接口类型-》反射对象
	fmt.Println(reflect.TypeOf(author))//string
	fmt.Println(reflect.ValueOf(author))//drave
	//经历了反射对象-》空接口类型-》基本类型
	fmt.Println(reflect.ValueOf(author).Interface().(string))//还原
	}

3.要修改反射对象,其值必须可修改
反射的意义:
因为反射在工程实践中,目的一就是可以获取到值和类型,其二就是要能够修改他的值,否则反射出来只能看,不能动,就会造成这个反射很鸡肋。例如:应用程序中的配置热更新,必然会涉及配置项相关的变量变动,大多会使用到反射来变动初始值

func main(){
	i:=1
	v:=reflect.ValueOf(i)
	v.SetInt(10)
	fmt.Println(i)//这样会报错,因为go中函数传参是值传递,这里的两个i没有任何关系,正确的应该是
	i:=1
	v:=reflect.ValueOf(&i)//获取变量指针
	v.Elem().SetInt(10)//v.Elem()获取指针指向的变量,然后SetInt更新值
	fmt.Println(i)	
	//借助以下来理解
	i:=1
	v:=&i//获取变量指针
	*v=10//*v获取变量指针指向的值,即1,并修改
	//从这里可以发现&i一般是等式右边,指变量地址;*v是等式左边,指地址的值
	}
其他函数的意思
func (v Value) NumField() int
返回v这个结构体类型值的字段数,如果v的Kind不是Struct会panic
 (v Value) Field(i int) Value
返回结构体的第i个字段(的Value封装)。如果v的Kind不是Struct或i出界会panic
func (v Value) NumMethod() int
返回v的方法数量
func (v Value) Method(i int)Value
返回v的第i个方法
func (v Value) MethodByName(name string) Value

示例:通过反射来遍历结构体

package main

import (
	"fmt"
	"reflect"
)

//使用反射来遍历结构体的字段,调用结构体的方法,修改结构体字段的值,并获取结构体标签的值

//定义结构体
type Student struct {
	Name string	`json:"name"`  // 是 ` ` (tab键上的~按键) ,不是 ' '
	Sex string `json:"sex"`
	Age int `json:"age"`
	Sal float64 `json:"sal"`
}

func (s Student) GetName() string  {  //第0个方法
	fmt.Println("该结构体Name字段值为:",s.Name)
	return s.Name
}

func (s *Student) Set(newName string,newAge int,newSal float64){  //第2个方法
	s.Name = newName
	s.Age = newAge
	s.Sal = newSal
	s.Print()
}

func (s Student) Print()   { //第1个方法
	fmt.Println("调用 Print 函数输出结构体:",s)
}

//反射获取结构体字段、方法,并调用
func testReflect(b interface{})  {
	rVal := reflect.ValueOf(b).Elem()
	rValI := reflect.ValueOf(b)
	rType := reflect.TypeOf(b).Elem()

	//判断是否是结构体在进行下一步操作
	if rType.Kind() != reflect.Struct{
		fmt.Println("该类型不是结构体。所以无法获取字段及其方法。")
	}

	//获取字段数量
	numField := rVal.NumField()
	fmt.Printf("该结构体有%d个字段\n",numField)
	//遍历字段
	for i := 0; i < numField; i++ {
		//获取字段值、标签值
		rFieldTag := rType.Field(i).Tag.Get("json")
		if rFieldTag != "" {
			fmt.Printf("结构体第 %v 个字段值为:%v ," +
				"Tag‘json’名为:%v\n",i,rVal.Field(i),rFieldTag)
		}
	}

	//获取方法数量
	numMethod := rValI.NumMethod()   //用指针可以获取到指针接收的方法
	fmt.Printf("该结构体有%d个方法\n",numMethod)

	//调用方法(方法顺序 按照ACSII码排序)
	rVal.Method(0).Call(nil)
	rVal.Method(1).Call(nil)

	//参数也需要以 Value 的切片 传入
	params  := make([]reflect.Value ,3)
	params[0] = reflect.ValueOf("hhhh")
	params[1] = reflect.ValueOf(28)
	params[2] = reflect.ValueOf(99.9)
	rValI.Method(2).Call(params)

	rVal.Method(1).Call(nil)
}

func main() {
	stu := Student{
		Name: "莉莉安",
		Sex: "f",
		Age: 19,
		Sal: 98.5,
	}

	//调用编写的函数并输出
	testReflect(&stu)
	fmt.Println("主函数输出结构体 Student :",stu)
}

其他的根据网上资料用到再学
https://www.cnblogs.com/l1ng14/p/13921985.html 反射包的其他函数及属性

1.4 类型断言与转换

首先,让我们看看它们长什么样……

下面是一个类型断言的例子:

var greeting interface{} = "hello world"
greetingStr := greeting.(string)

接着看一个类型转换的例子:

greeting := []byte("hello world")
greetingStr := string(greeting)

最明显的不同点是他们具有不同的语法(variable.(type) vs type(variable) )。

1.4.1 类型断言

类型断言用于断言变量是属于某种类型。类型断言只能发生在interface{}类型上。上面类型断言的例子,greeting是一个interface{}类型,我们为其分配了一个字符串。现在,我们可以认为greeting实际上是一个string,但是对外展示的是一个interface{}。如果我们想获取greeting的原始类型,那么我们可以断言它是个string,并且此断言操作会返回其string类型。
这意味着在做类型断言的时候,我们应该知道任何变量的基础类型。但是情况并非总是这样的,这就是为什么类型断言操作实际上还返回了第二个可选值的原因。

var greeting interface{} = "42"
greetingStr, ok := greeting.(string)

第二个值是一个布尔值,如果断言正确,返回 true ,否则返回 false。

以下是一个类型判断的例子,

var greeting interface{} = 42

switch g := greeting.(type) {
  case string:
    fmt.Println("g is a string with length", len(g))
  case int:
    fmt.Println("g is an integer, whose value is", g)
  default:
    fmt.Println("I don't know what g is")
}

1.4.2 类型转换

只有当基础数据结构类型相同,类型之间才可以相互转换。

// `myInt` 是一个新类型,它的基类型是 `int`
type myInt int

// AddOne 方法适用于 `myInt` 类型,不适用于 `int` 类型
func (i myInt) AddOne() myInt { return i + 1}

func main() {
    var i myInt = 4
    fmt.Println(i.AddOne())
}

 var i myInt = 4
originalInt := int(i)
//myInt的基础类型为int,因此与int基础类型相同,可以转换
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go语言基础(一)之函数调用、传参、反射机制、类型断言与转换 的相关文章

  • 带 cookie 身份验证的 Gorilla websocket

    这是我的设置 我正在构建一个带有用户登录的服务 使用 Negroni 和 Gorilla 登录后 用户会获得一个会话 cookie 服务器使用该会话 cookie 来授权受保护的端点 受保护的端点之一允许用户 客户端与服务器打开 Webso
  • golang:使用 gin 路由器服务 net.Conn

    我有一个处理传入 TCP 连接的函数 func Handle conn net Conn error 另外 我有一个初始化的 gin 路由器 带有已实现的句柄 router gin New router GET router POST Th
  • Go 中数组的嵌套结构

    我已经开始使用https mholt github io json to go https mholt github io json to go 将 API JSON 转换为 go 结构 我真的很喜欢它 但是我对如何初始化如下所示的报告定义
  • Ajax 将文件上传到内容类型为 Multipart 的 GoLang 服务器

    我正在尝试使用多部分表单将音频文件上传到 Golang 服务器 然而 Go 返回错误 multipart NextPart bufio buffer full 我相信这表明我的 Javascript 请求中存在不属于多部分格式的内容 这是我
  • 使用 google.protobuf.Timestamp 在 Go 中解析带有时区偏移的日期时间戳

    我正在创建一个将使用 GRPC 和 protobuf 的 Go 应用程序 我的 RPC 服务应获取包含类型的消息google protobuf Timestamp 解析它并最终将其保存在数据库中或对其执行更多操作 我对什么被认为是该类型的有
  • ReverseProxy取决于golang中的request.Body

    我想构建一个 http 反向代理 它检查 HTTP 主体 然后将 HTTP 请求发送到它的上游服务器 你怎么能在 Go 中做到这一点 初始尝试 如下 失败 因为 ReverseProxy 复制传入请求 修改它并发送 但正文已被读取 func
  • 初始化嵌套匿名结构

    我有一个 json 作为 fields time id status customerId additionalDetail pageInfo start 0 rows 1000 我想将我的结构编组到上面的 json 并创建如下结构 typ
  • 检查值是否实现接口的说明

    我读过 Effective Go 和其他类似这样的问答 golang接口合规性编译类型检查 https stackoverflow com questions 17994519 golang interface compliance com
  • Go io.Pipe 的缓冲版本

    有缓冲版本吗io Pipe https golang org pkg io Pipe 在标准库或第三方库中 在我推出自己的库之前 上下文 我正在尝试使用这个解决方案 https stackoverflow com a 36229262 15
  • 如何分析 VSCode 中函数的性能

    我用 C Golang 编写了一个程序 如何找到占用最高 CPU 周期的函数 目的是提高正在执行的程序的性能 2021 年 10 月 金香儿哈娜 https github com hyangah宣布 tweet https twitter
  • GoQt 致命错误:QAbstractAnimation:没有这样的文件或目录

    我尝试编译 Qt 来开发桌面应用程序 我按照 Qt 网站上的官方 wiki 指南的说明进行操作 当我尝试go run示例文件夹中的示例 我收到错误 去运行 home pinkya rabbit workspace go1programs s
  • 如何在 Go 中解组具有多个项目的简单 xml?

    我想从以下 xml 中获取人物 People 的一部分
  • 鸭子在 Go 中打字

    我想写一个Join函数接受任意对象String 方法 package main import fmt strings type myint int func i myint String string return fmt Sprintf
  • 解组转义 XML

    在 Go 中 我将如何解码此 XML 响应 我尝试过建立一个自定义UnMarshal方法在我的Answerstruct 但我运气不太好
  • 为什么 Go 禁止取 (&) 映射成员的地址,却允许取 (&) 切片元素?

    Go 不允许获取地图成员的地址 if I do this p mm abc Syntax Error cannot take the address of mm abc 理由是 如果 Go 允许使用此地址 那么当地图后台存储增长或缩小时 该
  • 在 Go 中初始化嵌入结构

    我有以下内容struct其中包含一个net http Request type MyRequest struct http Request PathParams map string string 现在我想初始化匿名内部结构http Req
  • 如何在 Linux 中编写文本模式 GUI? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 当我编写脚本 程序时 我经常想弹出一个简单的文本 gui 来提示输入 我该怎么做 例如 来自 Shel
  • 如何在golang中创建一个充满“000000...”数据的10MB文件?

    我打算在日志或磁盘队列等系统中使用 fdatasync 首先是在 ext4 等文件系统中创建一个带有 000000 的 10MB 文件 但我不知道如何正确地做到这一点 jnml fsc r630 src tmp SO 16797380 ls
  • 如何在golang中解析JSON而不需要解组两次

    我有一个 Web 套接字连接 它在 JSON 对象中发送不同类型的消息 并且我想将内容解组到一些已知的结构中 为此 我认为我应该执行以下操作 步骤 1 将 JSON 解组为通用映射 字符串 接口 步骤 2 找到我要找的钥匙 步骤 3 尝试将
  • 为什么 json.Unmarshal 返回映射而不是预期的结构?

    看看这个游乐场 http play golang org p dWku6SPqj5 http play golang org p dWku6SPqj5 基本上 我正在工作的图书馆收到了interface 作为参数 然后需要json Unma

随机推荐

  • 摸不着头脑,flatMap处理后居然无法去重(原来是数据库添加字段的时候多了个空格= =)

    前言 这应该是一个bug 这是一篇毫无营养的博客 当我正在尝试从页面中获取作者时 发现之前应该被Set包装的作者字符串居然发生了重复 于是我赶紧回到源码处 并加了条log日志 开始排查问题 我的代码是这样的 查作者 绝对也会有 Set
  • 死锁产生的四个必要条件(缺一不可)

    死锁产生必须同时满足四个条件 只要其中任意一条不成立 死锁就不会发生 1 互斥条件 进程要求对所分配的资源进行排他性控制 即在一段时间内某项资源只被 一个进程所占有 此时若有其他进程请求该资源 则请求进程只能等待 如图一 2 非抢占 进程所
  • 解决OptiSystem安装、使用过程中遇到的问题

    系统环境 Win10系统 问题1 在上一篇文章 Optisystem7 0安装教程 Win10系统 中提到 安装过程中会弹出一个对话框 需要点击 忽略 但是安装过程中出现下图错误 错误代码 0x3 点击忽略 仍然会继续弹出这个对话框 或者第
  • Flink实战-(1)Flink-CDC MySQL同步到MySQL(select)

    背景 基于select语句的Flink CDC 适用于数据同步的全量同步的场景 可以结合 Azkaban 或者dolphin scheduler 做定时调度 T 1 数据同步 1 maven
  • Verdi之nTrace/nSchema

    目录 3 nTrace介绍 3 1 启动Verdi 3 2查看Verdi中的设计结构 3 3查看Verdi中的验证结构 3 4 查找模块和trace信号 3 5 查找string 3 6 信号drive load 3 7 快速查看设计有哪些
  • 使用 javascript 将鼠标指针移动到特定位置

    请注意 无法将鼠标指针移动到 JavaScript 中的特定位置 主要原因是它会给用户带来安全问题并损害用户体验 在这篇文章中 我们将创建一个假的或自定义的鼠标指针 它可能看起来类似于默认系统的鼠标指针 然后我们将使用 JavaScript
  • 使用TensorBoard可视化模型

    为了了解发生的情况 我们在模型训练期间打印一些统计数据 以了解训练是否在进行中 但是 我们可以做得更好 PyTorch 与 TensorBoard 集成在一起 TensorBoard 是一种工具 用于可视化神经网络训练运行的结果 读取数据并
  • Q81:“三角形网格”之“PLY文件”

    81 1 引入 在 Q79 和 Q80 中用三角形网格细分曲面时 都是将每一个三角形的三个顶点的坐标都保存在内存中 这句话有两个重点 其一 每个三角形的三个顶点的坐标都计算了一次 但是 每个顶点都是被好几个三角形公用的 所以每个顶点的坐标被
  • 试题:网易笔试的一道题目

    写一个程序 打印出以下的序列 a b c d e z a b a c a d a e a z b c b d b z c d y z a b c a b d a b z a c d x y z a b c d x y z 这道题是从luci
  • mysql通用日志不打印_解决logback不打印mybatis的SQL日志的问题

    工作这么多年 今天还是因为Logback的这个问题稍微卡了一下 惭愧 问题描述 logback配置了如下信息 此处省略File Appender内容 logbase sql d yyyy MM dd log 30 d yyyy MM dd
  • SQL 语句中 where 条件后 写上1=1 是什么意思

    在编程过程中 经常会在代码中使用到 where 1 1 这是为什么呢 SQL注入 初次看到这种写法的同学肯定很纳闷 加不加where 1 1 查询不都一样吗 例如 select from customers 与 select from cu
  • Windows/Linux 部署Nacos遇到的问题及解决方法

    nacos的版本采用的是2 1 2 本片只记录部署过程遇到的问题 不涉及部署过程 Linux遇到的问题 com alibaba nacos core distributed raft exception JRaftException jav
  • C++项目(有注释超详细)

    规范代码 定义函数或者类尽量放到头文件中 这样不容易出现重复命名和代码冗杂的问题 pragma once include
  • 全新的eMPP(Elastic MPP),超越MPP的超弹性架构

    大数据时代 的概念最早由著名咨询公司麦肯锡提出 麦肯锡表示 数据已渗透到今天的每个行业和业务功能领域 并已成为重要的生产要素 数据在精巧的算法中被挖掘 数据分析变得至关重要 大家开始达成一个共识 数据计算 能够找到新发现 博思艾伦咨询公司的
  • 第1174期AI100_机器学习日报(2017-12-05)

    AI100 机器学习日报 2017 12 05 kegra 使用keras通过深度学习构建知识图谱 ChatbotsChina 图数据中的推理 微软亚洲研究院 浅谈NLP中条件语言模型 Conditioned Language Models
  • 第七课:BootRom的烧录

    目录 2 5 烧录BootRom 2 5 1 P2020 e500核 上电启动及boot流程 2 5 2 烧录BootRom到NorFlash 2 5 2 1 CodeWarrior的介绍
  • QT定时器

    QTimer使用 添加头文件 include
  • 推荐一个很适合程序员的副业!

    推荐一个超级赞的副业就是有声书录制 从2013年到现在已经火了9年时间 可谓是源远流长 这个兴趣爱好衍生出来的副业已经承载了上百万小白从业人员 头部主播的年收入都破了百万 有声书录制的发展历程可以概括为 或许曾经混沌 但必定未来可期 判断一
  • windows核心编程-杨波-专题视频课程

    windows核心编程 422人已学习 课程介绍 SDK 软件开发工具包 Software Development Kit SDK 一般是一些被软件工程师用于为特定的软件包 软件框架 硬件平台 作业系统等创建应用软件的开发工具的集合 MFC
  • Go语言基础(一)之函数调用、传参、反射机制、类型断言与转换

    Go语言基础 一 之函数调用 传参 反射机制 1 1 函数调用 package main func myFunction a b int int int return a b a b func main myFunction 66 77 使