当前位置: 首页 > article >正文

断言与反射——以golang为例

断言

x.(T) 检查x的动态类型是否是T,其中x必须是接口值。

简单使用

func main() {var x interface{}x = 100value1, ok := x.(int)if ok {fmt.Println(value1)}value2, ok := x.(string)if ok {//未打印fmt.Println(value2)}
}

需要注意如果不接受第二个参数就是OK,这里失败的话则会直接panic,这里还存在一种情况就是x为nil同样会panic。

func main() {var x interface{}x = "Hello World"value := x.(int)fmt.Println(value)
}
panic: interface conversion: interface {} is string, not int

所以就有这种写法

switch写法

func JudgeType(a interface{}) {switch value := a.(type) {case nil:fmt.Println("Type is nil")case int:fmt.Println("int", value)case string:fmt.Println("string:", value)case A:fmt.Println("类型A:", value)case *A:fmt.Println("指针A", value)default:fmt.Println("未匹配")}
}

注意 断言好像是只能一层一层去处理的 不能一次直接

package mainimport ("encoding/json""fmt"
)func main() {json_str := `{"font_size": 0.4,"lang": "zh","version": "en-v1.2.0.4-t0.3.c","body": [{"content": "最近很多人问我这个概念"},{"content": "在过去的一年里我一直很喜欢"}]}`var json_map map[string]interface{}json.Unmarshal([]byte(json_str), &json_map)//这里直接一步到位 断言成[]map[string]interface {}  会报错 panic: interface conversion: interface {} is []interface {}, not []map[string]interface {}//同理[]map[string]string也不可以body := json_map["body"].([]interface{})for _, item := range body {itemMap := item.(map[string]interface{}) //map[string]string依然报错fmt.Println(itemMap["content"])}}

在这个例子中就是 我们每次只能断言一个级别 比如第一层断言是个切片[],第二层断言是个map[string]

以及注意 interface类型 都要加{}

但是 在处理json的时候

	type body_struct []map[string]stringvar json_map map[string]body_structjson.Unmarshal([]byte(json_str), &json_map)

可以直接这样,猜测是json这个包内部进行了处理吧

反射

前置知识

用到了前面断言的知识

Go语言中的变量是分为两部分的:

• 类型信息:预先定义好的元信息。

• 值信息:程序运行过程中可动态变化的。

在 GoLang 的反射机制中,任何接口值都由是一个具体类型和具体类型的值两部分组成的。

在这里插入图片描述
golang变量包含两个属性 type和value,这是一个pair对。

type Reader interface {ReadBook( )
}
type Writer interface {WriteBook()
}
//一个具体的结构体
type Book struct {
}
//Book类实现了Reader接口
func(this *Book)ReadBook(){fmt.Println("Read a Book")
}
Book类实现了Writer 接口
func(this *Book)WriteBook(){fmt.Println("Write a Book")
}
func main(){//b:pair<type:Book,value:book{}地址>b := &Book{}//r: pair<type:, value:>var r Reader//r:pair<type:Book, value:book{}地址>r = br.ReadBook()var w writer//r: pair<type:Book,value:book{}地址>w=r.(Writer)//此处的断言为什么会成功?因为w与r 具体的type是一致

简单的理解就是 Book实现了两个接口,断言成功就是reader指向的book对象可以转为writer

是什么

反射是静态语言具有动态属性的体现

反射是指在程序运行期间对程序本身进行访问和修改的能力。正常情况程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取自身的信息。支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们

有时我们需要写一个函数,这个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,也可能布局未知,也有可能这个类型在我们设计函数时还不存在,这个时候我们就可以用到反射

反射的功能

  • 反射可以在程序运行期间动态的获取变量的各种信息,比如变量的类型 类别

  • 如果是结构体,通过反射还可以获取结构体本身的信息,比如结构体的字段、结构体的方法、结构体的 tag。

  • 通过反射,可以修改变量的值,可以调用关联的方法

reflect包与基本用法

在 GoLang 中,反射的相关功能由内置的 reflect 包提供,任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成,并 且 reflect 包 提 供 了

  • reflect.TypeOf
  • reflect.ValueOf
    两个重要函数来获取任意对象的 Value 和 Type

在这里插入图片描述

%T不也可以获取类型么?----可能%T就是通过反射来得到的

reflect.TypeOf()

使用 reflect.TypeOf()函数可以接受任意 interface{}参数,可以获得任意值的类型对象(reflect.Type),程序通过类型对象可以访问任意值的类型信息

在反射中关于类型还划分为两种:类型(Type)和种类(Kind)

因为在 Go 语言中我们可以使用 type 关键字构造很多自定义类型,而种类(Kind)就是指底层的类型,但在反射中,

当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind)。 举个例子,我们定义了两个指针类型和两个结构体类型,通过反射查看它们的类型和种类。

Go 语言的反射中像数组、切片、Map、指针等类型的变量,它们的.Name()都是返回空

import ("fmt""reflect"
)func reflectFn(x interface{}) {// 反射获取任意变量类型v := reflect.TypeOf(x)name := v.Name() // 类型名称kind := v.Kind() // 种类(底层类型)fmt.Printf("类型是%v,类型名称是%v,种类是%v \n", v, name, kind)}// 自定义一个myInt类型
type myInt int// Person结构体
type Person struct {Name stringAge  int
}func main() {a := 10b := "s"// 打印基本类型reflectFn(a) // 类型是int,类型名称是int,种类是intreflectFn(b) // 类型是string,类型名称是string,种类是string// 打印自定义类型和结构体类型var i myInt = 3var p = Person{"1",2,}reflectFn(i) // 类型是main.myInt,类型名称是myInt,种类是intreflectFn(p) // 类型是main.Person,类型名称是Person,种类是struct// 打印指针类型var f = 25reflectFn(&f) // 类型是*int,类型名称是,种类是ptr}
与前面x.(type)区别
a.(type)

是类型断言中的特殊语法,仅在 switch 语句中使用,用于通过接口变量获取其动态类型。例如:

switch v := a.(type) {
case int:fmt.Println("int:", v)
case string:fmt.Println("string:", v)
}

该语法直接通过接口值的动态类型进行分支判断‌46。

‌reflect.TypeOf(a)

是反射包中的函数,返回 reflect.Type 接口类型的对象,用于获取任意值的类型信息。例如:

typeOfA := reflect.TypeOf(a)
fmt.Println(typeOfA.Name(), typeOfA.Kind())

该函数通过反射机制解析值的类型,适用于动态类型检查‌12。

功能与灵活性‌

.(type)仅能判断接口变量的动态类型,无法获取更详细的类型元信息(如结构体字段、方法等)。
需在代码中显式列出所有可能的类型分支,适用于类型已知或有限的场景‌

`‌reflect.TypeOf‌``返回完整的类型元信息,包括类型名称(Name)、种类(Kind)、结构体字段、方法等。
支持动态处理任意类型,适用于编写通用代码(如序列化、ORM 框架)或需要深度类型分析的场景‌

性能开销‌
‌a.(type)‌
类型断言是 Go 语言的内置语法,性能开销极低,几乎等同于普通的条件判断‌。

‌reflect.TypeOf‌
反射操作需要运行时动态解析类型信息,涉及额外的内存分配和间接调用,性能开销较高。应避免在性能敏感的场景中使用‌

reflect.ValueOf() 获取原始值

reflect.ValueOf()返回的是 reflect.Value 类型,其中包含了原始值的值信息。reflect.Value 与原始值之间可以互相转换
在这里插入图片描述

func reflectValue(x interface{}) {// 通过反射获取到值v := reflect.ValueOf(x)fmt.Printf("%v, %T \n", v, v) // 10, reflect.Value,获取到的类型是reflect.Valuefmt.Printf("%v,%T", v.Int(), v.Int()) // 10,int64,获取到原始值和类型,因为传入是数字,所以是v.Int()
}
func main() {var i = 10reflectValue(i)
func reflectValue(x interface{}) {v := reflect.ValueOf(x)kind := v.Kind() // 获取种类// 判断底层种类  switch kind {// 是int类型case reflect.Int64:fmt.Println(v.Int())case reflect.Float64:fmt.Println(v.Float())case reflect.String:fmt.Println(v.String())}
}

set通过反射设置变量的值

import ("fmt""reflect"
)func reflectValue(x interface{}) {v := reflect.ValueOf(x)// 如果传入的值是一个指针地址,那需要通过Elem().Kind()获取具体种类,Elem()返回 Type 对象所表示的指针指向的数据// 如果只是v.kind,获取的到的是指针类型kind := v.Elem().Kind() // int64if kind == reflect.Int64 {//  int是SetInt  string是SetString等v.Elem().SetInt(3)}
}func main() {var i = 10// 值类型修改副本不会影响原始值,所以需要通过指针地址reflectValue(&i)fmt.Println(i) // 3}

import (
“fmt”
“reflect”
)

// studen结构体
type Student struct {
Name string json:"name"
Age int json:"age"
Score int json:"score"
}

// 结构体方法 获取学生信息
func (s Student) GetInfo() string {
return fmt.Sprintf(“姓名%v 年龄%v 成绩%v”, s.Name, s.Age, s.Score)

}

// 结构体方法 修改学生信息
func (s *Student) SetInfo(name string, age, score int) {
s.Name = name
s.Age = age
s.Score = score

}

// 结构体方法 打印
func (s Student) PrintInfo() {
fmt.Println(“print info”)

}

func PrintStructField(s interface{}) {
// 获取类型对象
t := reflect.TypeOf(s)
/*

	通过类型变量里面的Field获取结构体字段*/
// 通过类型变量.Field(下标)可以获取结构体的字段对象
field0 := t.Field(0)// 获取到结构体的Name字段对象
fmt.Println(field0) // {Name  string json:"name" 0 [0] false}fmt.Printf("%#v \n", field0) // reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0xe748c80), Tag:"json:\"name\"", Offset:0x0, Index:[]int{0}, Anonymous:false}
// 获取字段名称
fmt.Println(field0.Name) // Name
// 获取字段类型
fmt.Println(field0.Type) // string
// 获取字段tag - json类型
fmt.Println(field0.Tag.Get("json")) // name/*通过类型变量里面的FieldByName获取结构体字段
*/
// FieldByName返回两个值,一个是具体的值,一个是是否成功
field1, ok := t.FieldByName("Age")
if ok {fmt.Println(field1.Name)            // 字段名称:Agefmt.Println(field1.Type)            // 字段类型:intfmt.Println(field1.Tag.Get("json")) // 字段的json类型的tag :age
}/*通过类型变量的NumField获取该结构体有多少个字段
*/var count = t.NumField()
fmt.Println(count) // 3

}

func main() {

var student = Student{"小李", 15, 100}
PrintStructField(student)

}

通过值变量获取结构体值的值信息#
func PrintStructField(s interface{}) {
/*
通过值变量获取结构体属性对应的值
*/
v := reflect.ValueOf(s)
// 方式一
fmt.Println(v.FieldByName(“Name”)) // 小李
fmt.Println(v.FieldByName(“Age”)) // 15
// 方式二 可以通过循环获取所有的属性值
fmt.Println(v.Field(2)) // 100

}
通过反射修改结构体的属性值#
func ReflectSetValue(s interface{}) {
// 类型对象
t := reflect.TypeOf(s)
// 值对象
v := reflect.ValueOf(s)
// 判断传入的结构体是否是指针类型,因为非指针是值类型,不能修改值,必现使用指针类型
if t.Kind() != reflect.Ptr {
fmt.Println(“传入的不是指针类型”)
return

	// 判断传入的指针是不是结构体指针
} else if t.Elem().Kind() != reflect.Struct {fmt.Println("传入的不是结构体指针")return
}
// 获取Name字段的指针值
name := v.Elem().FieldByName("Name")
// 修改属性值
name.SetString("小王")

}

func main() {

var student = Student{"小李", 15, 100}
// 如果传入一个值接收者,没有办法修改结构体的值,如果要修改对应值,需要传入指针接收者
ReflectSetValue(&student)
fmt.Println(student.Name) // 小王

}

通过类型变量获取结构体方法#
// 打印结构体方法
func PrintStructFn(s interface{}) {
t := reflect.TypeOf(s)

// 通过类型变量的Method(下标)获取结构体的方法
method0 := t.Method(0)    // 下标取的方法和结构体的顺序没有关系,和结构体的ASCII码有关系
fmt.Println(method0.Name) // 下标为0的方法名:GetInfo
fmt.Println(method0.Type) // func(main.Student) string// 通过MethodByName 获取结构体方法
// 该方法两个返回值,一个是方法名,一个是是否有该方法的状态
method1, ok := t.MethodByName("PrintInfo")
if ok {fmt.Println(method1.Name) // PrintInfofmt.Println(method1.Type) // func(main.Student)}
// 获取结构体一共有几个方法
fmt.Println(t.NumMethod()) // 2 Student结构体定义了3个方法,有两个接收者类型是结构体,有一个接收者类型是指针接收者,如果s接收的是值接收者,只能统计值接收者的方法数量,如果是指针接收者,可以统计所有的方法的数量

}

func main() {

var student = Student{"小李", 15, 100}
PrintStructFn(student)

}

通过值变量执行结构体方法#
func RunStructFn(s interface{}) {
v := reflect.ValueOf(s)
// 方法一 通过下标执行对应的方法,Call传递对应参数,nil代表没有参数
v.Method(1).Call(nil) // print info

// 方法二 通过MethodByName执行对应方法,返回值是一个切片
// 传入参数调用,Call方法传入的参数需要是一个reflect.Value类型的切片
var params []reflect.Value
params = append(params, reflect.ValueOf("小李"))
params = append(params, reflect.ValueOf(20))
params = append(params, reflect.ValueOf(95))
v.MethodByName("SetInfo").Call(params)fmt.Println(v.MethodByName("GetInfo").Call(nil)) // [姓名小李 年龄20 成绩95]

}

func main() {

var student = Student{"小李", 15, 100}
// 如果传入一个值接收者,没有办法修改结构体的值,如果要修改对应值,需要传入指针接收者
RunStructFn(&student)

}

应用场景

(1)动态类型检查

反射可以用于在运行时检查变量的类型,这在处理未知类型的数据时非常有用。例如,编写通用函数或库时,可能需要根据传入参数的类型执行不同的操作。

func checkType(data interface{}) {t := reflect.TypeOf(data)fmt.Println("Type:", t)
}
(2)动态调用方法

反射可以用于在运行时动态调用对象的方法,这在需要根据条件调用不同方法时非常有用

type MyStruct struct{}func (m *MyStruct) MyMethod() {fmt.Println("MyMethod called")
}func callMethod(obj interface{}, methodName string) {v := reflect.ValueOf(obj)method := v.MethodByName(methodName)if method.IsValid() {method.Call(nil)}
}
(3)结构体字段操作比如处理配置文件

反射可以用于在运行时动态访问和修改结构体的字段,这在处理配置文件、数据库映射等场景时非常有用。

type Person struct {Name stringAge  int
}func setField(obj interface{}, fieldName string, value interface{}) {v := reflect.ValueOf(obj).Elem()field := v.FieldByName(fieldName)if field.IsValid() && field.CanSet() {field.Set(reflect.ValueOf(value))}
}
动态绑定配置字段‌

通过反射动态解析配置文件(如 YAML、JSON),将键值对自动映射到预定义结构体的字段中,无需手动逐字段赋值。
‌典型实现‌:

读取配置文件内容后,遍历结构体的反射元数据,匹配键名与字段名(支持大小写转换、json/yaml 标签解析)‌。
处理嵌套结构体时,递归遍历子结构体字段,实现复杂配置的自动加载‌8。

支持热加载配置‌

因为已经变成二进制文件了 配置新消息变成了一个内存中的结构体 所以我们要用反射才能找到它?或者 因为外部是不确定的 你不知道传进来的配置文件是啥样的

通过反射动态更新配置对象,实现运行时重载配置文件(如 SIGHUP 信号触发)而不重启服务。

‌实现逻辑‌:

  • 监听配置文件变化,重新读取文件内容并生成新配置对象。
  • 通过反射对比新旧配置对象差异,仅更新发生变化的字段值(避免全局替换导致状态不一致)‌
统一配置处理接口‌

编写通用配置解析函数,支持多种格式(JSON/YAML/TOML)的自动适配。
‌代码示例‌:

func LoadConfig(filePath string, config interface{}) error {data, _ := os.ReadFile(filePath)  // 读取文件val := reflect.ValueOf(config).Elem()// 根据文件后缀选择解析逻辑(如解析为 map[string]interface{})parsedData := parseByFileType(filePath, data)  // 反射遍历结构体字段并赋值for key, value := range parsedData {field := val.FieldByName(strings.Title(key))  if field.IsValid() && field.CanSet() {field.Set(reflect.ValueOf(value).Convert(field.Type()))  }}return nil
}
// 调用示例:LoadConfig("config.yaml", &ServerConfig{})  

‌说明‌:通过反射的 FieldByName 和 Set 方法实现键值动态映射,支持类型转换(如字符串转 int)‌。

处理环境变量与默认值‌

结合反射实现配置优先级逻辑(如环境变量 > 配置文件 > 默认值)。

‌实现方式‌:

-遍历结构体字段,检查是否存在 env 标签(如 env:“PORT”),优先从环境变量读取值‌。
若未配置环境变量或文件字段,通过反射检查并设置字段的默认值(如 default:“8080” 标签)‌。

‌动态校验配置合法性‌

利用反射实现字段类型校验或自定义规则检查(如端口号范围、必填字段)。
‌示例逻辑‌:

func ValidateConfig(config interface{}) error {t := reflect.TypeOf(config).Elem()v := reflect.ValueOf(config).Elem()for i := 0; i < t.NumField(); i++ {field := t.Field(i)value := v.Field(i)// 检查必填标签(如 `required:"true"`)if field.Tag.Get("required") == "true" && value.IsZero() {return fmt.Errorf("字段 %s 必填", field.Name)}}return nil
}

‌用途‌:防止因配置缺失或格式错误导致服务启动失败‌58。

注意事项

‌性能开销‌:反射操作比静态代码慢,建议在初始化阶段或低频热加载场景使用,避免高频调用‌

(4)序列化与反序列化

反射可以用于实现通用的序列化和反序列化功能,例如将结构体转换为JSON或从JSON解析为结构体

func toJSON(obj interface{}) string {v := reflect.ValueOf(obj)t := reflect.TypeOf(obj)var result stringfor i := 0; i < v.NumField(); i++ {field := t.Field(i)value := v.Field(i)result += fmt.Sprintf("%s: %v\n", field.Name, value.Interface())}return result
}
(5)插件系统

反射可以用于实现插件系统,动态加载和调用插件中的函数或方法。

func loadPlugin(pluginPath string, functionName string) {p, err := plugin.Open(pluginPath)if err != nil {log.Fatal(err)}f, err := p.Lookup(functionName)if err != nil {log.Fatal(err)}f.(func())()
}
(6)依赖注入

反射可以用于实现依赖注入框架,动态地将依赖注入到对象中。

type Service struct {Dependency *Dependency
}func injectDependency(service interface{}, dependency interface{}) {v := reflect.ValueOf(service).Elem()field := v.FieldByName("Dependency")if field.IsValid() && field.CanSet() {field.Set(reflect.ValueOf(dependency))}

相关文章:

断言与反射——以golang为例

断言 x.(T) 检查x的动态类型是否是T&#xff0c;其中x必须是接口值。 简单使用 func main() {var x interface{}x 100value1, ok : x.(int)if ok {fmt.Println(value1)}value2, ok : x.(string)if ok {//未打印fmt.Println(value2)} }需要注意如果不接受第二个参数就是OK,这…...

【家政平台开发(27)】商务部信用对接、法律咨询与视频面试功能开发全攻略

本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质量,…...

【数据结构】排序算法(下篇·开端)·深剖数据难点

前引&#xff1a;前面我们通过层层学习&#xff0c;了解了Hoare大佬的排序精髓&#xff0c;今天我们学习的东西可能稍微有点难度&#xff0c;因此我们必须学会思想&#xff0c;我很受感慨&#xff0c;借此分享一下&#xff1a;【用1520分钟去调试】&#xff0c;如果我们遇到了任…...

山东大学软件学院创新项目实训开发日志(9)之测试前后端连接

在正式开始前后端功能开发前&#xff0c;在队友的帮助下&#xff0c;成功完成了前后端测试连接&#xff1a; 首先在后端编写一个测试相应程序&#xff1a; 然后在前端创建vue 并且在index.js中添加一下元素&#xff1a; 然后进行测试&#xff0c;测试成功&#xff1a; 后续可…...

【VUE3】Eslint 与 Prettier 的配置

目录 0 前言 1 VSCode 中的 Eslint 与 prettier 插件 2 两种方案 3 eslint.config.js 4 eslint-plugin-prettier 插件 5 eslint-config-prettier 插件 6 安装插件命令 7 其他配置 8 参考资料 0 前言 黑马程序员视频地址&#xff1a;160-Vue3大事件项目-ESlint配合P…...

蓝桥杯C++组算法知识点整理 · 考前突击(上)【小白适用】

【背景说明】本文的作者是一名算法竞赛小白&#xff0c;在第一次参加蓝桥杯之前希望整理一下自己会了哪些算法&#xff0c;于是有了本文的诞生。分享在这里也希望与众多学子共勉。如果时间允许的话&#xff0c;这一系列会分为上中下三部分和大家见面&#xff0c;祝大家竞赛顺利…...

springboot调用python文件,python文件使用其他dat文件,适配windows和linux,以及docker环境的方案

介绍 后台是用springboot技术&#xff0c;其他同事做的算法是python&#xff0c;现在的需求是springboot调用python&#xff0c;python又需要调用其他的数据文件&#xff0c;比如dat文件&#xff0c;这个文件是app通过蓝牙获取智能戒指数据以后&#xff0c;保存到后台&#xf…...

GSO-YOLO:基于全局稳定性优化的建筑工地目标检测算法解析

论文地址:https://arxiv.org/pdf/2407.00906 1. 论文概述 《GSO-YOLO: Global Stability Optimization YOLO for Construction Site Detection》提出了一种针对建筑工地复杂场景优化的目标检测模型。通过融合全局优化模块(GOM)​、稳定捕捉模块(SCM)​和创新的AIoU损失函…...

Python 中使用单例模式

有这么一种场景&#xff0c;Web服务中有一个全局资源池&#xff0c;在需要使用的地方就自然而言引用该全局资源池即可&#xff0c;此时可以将该资源池以单例模式实现。随后&#xff0c;需要为某一特殊业务场景专门准备一个全局资源池&#xff0c;于是额外复制一份代码新建了一个…...

系统思考—提升解决动态性复杂问题能力

感谢合作伙伴的信任推荐&#xff01; 客户今年的人才发展重点之一&#xff0c;是提升管理者应对动态性、复杂性问题的能力。 在深入交流后&#xff0c;系统思考作为关键能力模块&#xff0c;最终被纳入轮训项目——这不仅是一次培训合作&#xff0c;更是一场共同认知的跃迁&am…...

Java基础 - 反射(2)

文章目录 示例5. 通过反射获得类的private、 protected、 默认访问修饰符的属性值。6. 通过反射获得类的private方法。7. 通过反射实现一个工具BeanUtils&#xff0c; 可以将一个对象属性相同的值赋值给另一个对象 接上篇&#xff1a; 示例 5. 通过反射获得类的private、 pro…...

Python proteinflow 库介绍

ProteinFlow是一个开源的Python库,旨在简化蛋白质结构数据在深度学习应用中的预处理过程。以下是其详细介绍: 功能 数据处理:支持处理单链和多链蛋白质结构,包括二级结构特征、扭转角等特征化选项。 数据获取:能够从Protein Data Bank (PDB)和Structural Antibody Databa…...

P1162 洛谷 填涂颜色

题目描述 思考 看数据量 30 而且是个二维的&#xff0c;很像走迷宫 直接深搜&#xff01; 而且这个就是搜连通块 代码 一开始的15分代码&#xff0c;想的很简单&#xff0c;对dfs进行分类&#xff0c;如果是在边界上&#xff0c;就直接递归&#xff0c;不让其赋值&#xff0c…...

docker安装nginx,基础命令,目录结构,配置文件结构

Nginx简介 Nginx是一款轻量级的Web服务器(动静分离)/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是占有内存少&#xff0c;并发能力强. &#x1f517;官网 docker安装Nginx &#x1f433; 一、前提条件 • 已安装 Docker&#xff08;dock…...

SQLI漏洞公开报告分析

文章目录 1. 闭合 )2. 邀请码|POST参数|时间盲注 | **PostgreSQL**3. POST|order by参数|布尔盲注|Oracle4. SOAP请求|MSSQL|布尔盲注5. MySQL 时间盲注漏洞6. GET|普通回显注入7. ImpressCMS 1.4.2 | CVE | POST | 布尔盲注8. Mysql | post | 布尔/时间盲注9. 登录口 | post |…...

SpringBoot项目部署之启动脚本

一、启动脚本方案 1. 基础启动方式 1.1 直接运行JAR java -jar your-app.jar --spring.profiles.activeprod优点&#xff1a;简单直接&#xff0c;适合快速测试缺点&#xff1a;终端关闭即终止进程 1.2 后台运行 nohup java -jar your-app.jar > app.log 2>&1 &…...

用Django和AJAX创建一个待办事项应用

用Django和AJAX创建一个待办事项应用 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 用Django和AJAX创建一个待办事项应用让我们创建一个简单的 Django 项目,其中包含不同类型的 A…...

JavaScript:游戏开发的利器

在近年来的科技迅速发展中&#xff0c;JavaScript 已逐渐成为游戏开发领域中最受欢迎的编程语言之一。它的跨平台特性、广泛的社区支持、丰富的库和框架使得开发者能够快速、有效地创建各种类型的游戏。本文将深入探讨 JavaScript 在游戏开发中的优势。 一、跨平台支持 JavaSc…...

C语言今天开始了学习

好多年没有弄了&#xff0c;还是捡起来弄下吧 用的vscode 建议大家参考这个配置 c语言vscode配置 c语言这个语言简单&#xff0c;但是今天听到了一个消息说python 不知道怎么debug。人才真多啊...

Elasticsearch 系列专题 - 第五篇:集群与性能优化

随着数据量和访问量的增长,单节点 Elasticsearch 已无法满足需求。本篇将介绍集群架构、性能优化方法以及常见故障排查,帮助你应对生产环境中的挑战。 1. 集群架构 1.1 节点角色(Master、Data、Ingest 等) Elasticsearch 集群由多个节点组成,每个节点可扮演不同角色: M…...

鸿蒙NEXT开发Preferences工具类(ArkTs)

import { AppUtil } from ./AppUtil; import dataPreferences from ohos.data.preferences; export const DEFAULT_PREFERENCE_NAME: string "SP_HARMONY_UTILS_PREFERENCES"; // Preferences实例的名称。/*** Preferences工具类* author CSDN-鸿蒙布道师* since 20…...

电商素材革命:影刀RPA魔法指令3.0驱动批量去水印,实现秒级素材净化

本文 去除水印实操视频展示电商图片水印处理的困境​影刀 RPA 魔法指令 3.0 强势登场​利用魔法指令3.0两步实现去除水印操作关于影刀RPA 去除水印实操视频展示 我们这里选择了4张小红书里面比较帅气的图片&#xff0c;但凡用过小红书的都知道&#xff0c;小红书右下角是会有小…...

前端面试题(七):什么是vuex,请解释一下它在Vue中的作用

Vuex 是一个专门为 Vue.js 应用程序开发的状态管理库。它可以集中管理应用的所有状态&#xff0c;并保证状态以一种可预测的方式发生变化。简单来说&#xff0c;Vuex 用来管理 Vue 应用中的数据&#xff08;即状态&#xff09;&#xff0c;使得数据的传递和共享更加清晰和可靠&…...

笔记:头文件与静态库的使用及组织方式

笔记&#xff1a;头文件与静态库的使用及组织方式 1. 头文件的作用 接口声明&#xff1a;提供函数、类、变量等标识符的声明&#xff0c;供其他模块调用。编译依赖&#xff1a;编译器需要头文件来验证函数调用和类型匹配。避免重复定义&#xff1a;通过包含保护&#xff08;如…...

ubuntu,react的学习(1)

在此目录下&#xff0c;开启命令行 /home/kt/react 如下操作 tkt4028:~/react$ npm create vitelatest task-manager -- --template react Need to install the following packages: create-vite6.3.1 Ok to proceed? (y) y> npx > cva task-manager --template react…...

【QT】QTreeWidgetItem的checkState/setCheckState函数和isSelected/setSelected函数

目录 1、函数原型1.1 checkState/setCheckState1.2 isSelected/setSelected2、功能用途3、示例QTreeWidget的checkState/setCheckState函数和isSelected/setSelected这两组函数有着不同的用途,下面具体说明: 1、函数原型 1.1 checkState/setCheckState Qt::CheckState QTr…...

CompletableFuture 和 List<CompletableFuture> allOf() join() get() 使用经验

CompletableFuture<Map<Menu, Map<IntentDetail, Double>>> xxx CompletableFuture.supplyAsync(() -> {Map<Menu, Map<IntentDetail, Double>> scores new ConcurrentHashMap<>();// 存储结果scores.computeIfAbsent(menu, k -> n…...

CExercise_09_结构体和枚举_2VS的Debug模式查看它的内存布局,采用结构体数组的方式存储信息,调用函数打印结构体数组.

题目&#xff1a; 下面结构体类型的变量的内存布局是怎样的&#xff1f;请使用VS的Debug模式查看它的内存布局 typedef struct stundent_s {int number;char name[25];char gender;int chinese;int math;int english; } Student;// 结构体对象的声明和初始化 Student s1 { 1, …...

SSRF漏洞技术解析与实战防御指南

一、SSRF漏洞简介 服务端请求伪造&#xff08;Server-Side Request Forgery, SSRF&#xff09; 是一种攻击者通过操控服务端发起非预期网络请求的安全漏洞。攻击者利用目标服务器的权限&#xff0c;构造恶意请求访问内网资源、本地系统文件或第三方服务&#xff0c;可能导致…...

CVA6:支持 Linux 的 RISC-V CPU CORE-V

RISC-V 是一种开源的可扩展指令集架构 (ISA)&#xff0c;在过去几年中广受欢迎。RISC-V 的主要特性之一是它采用整体架构中性设计&#xff0c;支持浮点运算、加载存储架构、符号扩展加速和多路复用器简化。这使得 RISC-V 成为 FPGA 上软处理器的经济实惠的选择。自 RISC-V ISA …...