CodeNavi 中代码表达式的节点和节点属性

本文分享自华为云社区《CodeNavi 中代码表达式的节点和节点属性》。作者:Uncle_Tom


1. 前期回顾

  • 《寻找适合编写静态分析规则的语言》
    根据代码检查中的一些痛点,提出了希望寻找一种适合编写静态分析规则的语言。

    • 可以满足用户对代码检查不断增加的各种需求;
    • 使用户能够通过增加或减少对检查约束条件的控制,实现快速调整检查中出现的误报和漏报;
    • 这种检查语言能够有较低的使用门槛,使用户更专注于检查业务,而不需要关注工具是如何实现的。

    我们称这种检查规则语言为:CodeNavi。文中给出了这种检查规则语言的两个应用场景,以此来说明这种检查规则语言如何满足用户在编写静态检查规则时的期望。

  • 《CodeNavi 规则的语法结构》
    介绍 CodeNavi 检查规则语言在编写规则的基本语法格式。CodeNavi 检查规则语言,通过对代码节点和节点属性的逻辑条件的组合来完成检查的约束条件,从而完成代码检查中需要满足的缺陷模式适配,找到满足要求的代码点。

  • 《CodeNavi 规则的基础节点和节点属性》
    介绍 CodeNavi 检查规则语言在编写时需要使用基础节点和节点属性,这些基础节点包括:节点类型、字面量、一般变量、枚举、成员变量(字段),以及数组。

  • 本文将继续介绍 CodeNavi 检查规则语言如何描述代码中的表达式。这些节点主要包括:

    • 3.1. 对象创建表达式(objectCreationExpression)
    • 3.2. 强制类型转换(castExpression)
    • 3.3. 类型判断表达式(instanceofExpression)
    • 3.4. 一元表达式(unaryOperation)
    • 3.5. 二元表达式(binaryOperation)
    • 3.6. 条件表达式/三目运算(ternaryOperation)
    • 3.7. 方法引用表达式(methodReferenceExpression)
    • 3.8. lambda表达式(lambdaExpression)
    • 3.9. 匿名内部类表达式(anonymousInnerClassExpression)

2. CodeNavi 中的节点和节点属性

程序是由空格分隔的字符串组成的序列。在程序分析中,这一个个的字符串被称为"token",是源代码中的最小语法单位,是构成编程语言语法的基本元素。

Token可以分为多种类型,常见的有关键字(如if、while)、标识符(变量名、函数名)、字面量(如数字、字符串)、运算符(如+、-、*、/)、分隔符(如逗号,、分号;)等。

我们只需要给代码的不同节点给出一个定义,然后通过条件语句来描述对这些节点的要求,使之符合缺陷检查的模式,就可以完成检查规则的定义。

2.1. 规则节点和节点属性图例

2.1.1. 节点

  • 图例

  • 节点和子节点都使用个图例

  • 规则语言中使用节点的 “英文名”,这样便于规则的编写。

2.2. 节点集

  • 图例

  • 节点的集合。

2.3. 属性

  • 图例

  • 规则语言中使用属性的 “英文名”,这样便于规则的编写。

3. 表达式

表达式是程序中用于产生一个值或执行一个操作的代码片段。表达式可以简单到只有一个字面量或变量,也可以复杂到包含多个操作符和子表达式。
表达式在程序中的作用非常广泛,它们是程序逻辑和数据处理的基础。表达式是构成程序的基本元素之一,它用于表示数据的计算或操作, 帮助开发者构建程序的逻辑和功能。

以下是表达式的一些主要作用:

  • 产生值
    表达式的主要作用是产生一个值。例如,5 + 3 产生值 8。

  • 算术运算
    表达式可以执行基本的算术运算,如加(+)、减(-)、乘(*)、除(/)、模(%)。

  • 关系运算
    表达式可以进行比较,产生布尔值(true或false)。例如,5 > 3 产生 true。

  • 逻辑运算
    表达式可以进行逻辑运算,如逻辑与(&&)、逻辑或(||)、逻辑非(!)。

  • 条件运算
    三元条件运算符(? :)允许基于条件表达式的结果选择两个值中的一个。例如,max = (a > b) ? a : b;。

  • 创建数组
    表达式可以用于声明和初始化数组。例如,new int[10];。

  • 创建对象
    表达式可以用于创建对象实例。例如,new Integer(10)。

  • 类型转换
    表达式可以进行类型转换,将一个类型的值转换为另一个类型。例如,(int) 3.14。

  • 创建和使用Lambda表达式
    Lambda表达式,允许以简洁的语法表示匿名函数。例如,() -> System.out.println(“Hello”);。

  • 控制流语句
    表达式的结果可以用于控制流语句,如if、while、for等。

  • 异常处理
    表达式可以与异常处理结合使用,如在try-catch块中。

3.1. 对象创建表达式(objectCreationExpression)

表达式用于创建对象实例。

  • 代码样例
new ArrayList();
  • 图例

名称描述值类型示例DSL 规则
name方法名字符串new MethodRefTypeTest();objectCreationExpression obc where
  obc.name == “MethodRefTypeTest”;
type返回值类型objectType节点new MethodRefTypeTest();objectCreationExpression obc where
  obc.type.name == “com.huawei.secbrella.kirin.test.sourcefile.methodRefType.MethodRefTypeTest”;
function调用的构造方法functionDeclaration节点public class MethodRefTypeTest {
  MethodRefTypeTest() {}

  public static void main(String[] args) {
    new MethodRefTypeTest();
}
objectCreationExpression obc where
  obc.function.name == “MethodRefTypeTest”;
arguments入参集合valueAccess类节点、functionCall节点等的集合new String(“Hello”);objectCreationExpression obc where
  obc.arguments.size() == 1;
arguments[n]第n个入参valueAccess类节点、functionCall节点等的集合new String(“Hello”);objectCreationExpression obc where
  obc.arguments[0].value == “Hello”;

3.2. 强制类型转换(castExpression)

类型强制转换(Type Casting)是指将一个类型的对象转换成另一个类型的对象。

  • 代码样例
double d = 10.5;
// 强制转换,需要显式指定目标类型
int i = (int) d;Object obj = new String("Hello");
// 安全的向下转型
String str = (String) obj; 
  • 图例

名称描述值类型示例DSL 规则
castType目标类型nodeArrayList second = (ArrayList) list;castExpression ce where
  ce.castType.name == “java.util.ArrayList”;
operand操作对象nodeArrayList second = (ArrayList) list;castExpression ce where
  ce.operand.name == “list”;

3.3. 类型判断表达式(instanceofExpression)

instanceof 关键字用于检查一个对象是否是特定类的实例或者是其子类的实例。

  • 代码样例

if (animal instanceof Dog) {((Dog) animal).makeSound();
}Object[] objects = new Object[10];
if (objects instanceof Object[]) {System.out.println("objects is an array of Object");
}
  • 图例

名称描述值类型示例DSL 规则
lhs左值任意节点father instanceof FatherinstanceofExpression ie where
  ie.lhs.name == “father”;
rhs右值,类型值全类名常量list instanceof ListinstanceofExpression ie where
  ie.rhs.name == “java.util.List”;

3.4. 一元表达式(unaryOperation)

一元表达式包含单个操作数。

  • 代码样例
// 一元算术表达式
// 递增:++x(将 x 的值增加 1)
// 递减:--x(将 x 的值减少 1)
// 前置递增/递减:int a = 5;
int b = ++a; // a 和 b 都是 6
int c = a--; // a 是 6, c 是 5// 后置递增/递减:int a = 5;
int b = a++; // a 是 6, b 是 5
int c = a--; // a 是 5, c 是 6// 一元逻辑表达式
// 逻辑非:!x(如果 x 为 true,则结果为 false,反之亦然)
boolean flag = true;
boolean notFlag = !flag; // notFlag 是 false// 一元位运算表达式
// 按位取反:~x(将 x 的每个位取反)
int num = 5; // 二进制表示为 101
int bitNotNum = ~num; // 结果是 -6, 二进制表示为 110...(32 个 1),因为整数溢出
  • 图例

名称描述值类型示例DSL 规则
isPrefix是否运算符前置布尔值a++;unaryOperation uo where uo.isPrefix == false;
operand操作对象任意节点i++;unaryOperation uo where uo.operand.name == “i”;
operator运算符字符串i++;unaryOperation uo where uo.operator == “++”;

3.5. 二元表达式(binaryOperation)

二元表达式包含两个操作数,并且返回一个单一的值。

  • 代码样例
// 算术二元表达式
// 加法:x + y
// 减法:x - y
// 乘法:x * y
// 除法:x / y
// 取模(求余数):x % y
int a = 10;
int b = 3;
int sum = a + b; // 13
int difference = a - b; // 7
int product = a * b; // 30
int quotient = a / b; // 3
int remainder = a % b; // 1// 比较二元表达式
// 等于:x == y
// 不等于:x != y
// 大于:x > y
// 小于:x < y
// 大于等于:x >= y
// 小于等于:x <= y
int x = 5;
int y = 10;
boolean isEqual = (x == y); // false
boolean isNotEqual = (x != y); // true
boolean isLessThan = (x < y); // true
boolean isGreaterThan = (x > y); // false
boolean isLessThanOrEqual = (x <= y); // true
boolean isGreaterThanOrEqual = (x >= y); // false// 逻辑二元表达式
// 逻辑与:x && y
// 逻辑或:x || y
// 逻辑异或:x ^ y
// 条件与(&):x & y(当 x 为 true 时才判断 y)
// 条件或(|):x | y(当 x 为 true 时,y 的结果将被忽略)
boolean condition1 = true;
boolean condition2 = false;
boolean andResult = condition1 && condition2; // false
boolean orResult = condition1 || condition2; // true
boolean xorResult = condition1 ^ condition2; // trueint num1 = 5;
int num2 = 3;
boolean bitAndResult = num1 & num2; // true, 因为 5 & 3 的二进制表示都是 101// 位运算二元表达式
// 位与:x & y
// 位或:x | y
// 位异或:x ^ y
// 位左移:x << n(将 x 的二进制表示向左移动 n 位)
// 位右移(算术):x >> n(将 x 的二进制表示向右移动 n 位,右边用符号位填充)
// 位右移(逻辑):x >>> n(将 x 的二进制表示向右移动 n 位,右边用0填充)
int number = 5; // 在内存中的表示是 101
int resultBitwiseAnd = number & 3; // 结果是 1, 因为 101 & 011 = 001
int resultBitwiseOr = number | 3; // 结果是 7, 因为 101 | 011 = 111
int resultBitwiseXor = number ^ 3; // 结果是 2, 因为 101 ^ 011 = 110int resultLeftShift = number << 1; // 结果是 10, 因为 101 向左移动一位变成 1010
int resultRightShift = number >> 1; // 结果是 2, 因为 101 向右移动一位变成 10
int resultRightShiftLogical = number >>> 1; // 结果是 2, 逻辑右移,忽略符号位// 赋值二元表达式
// 简单赋值:x = y
// 加等于:x += y
// 减等于:x -= y
// 乘等于:x *= y
// 除等于:x /= y
// 模等于:x %= y
// 位与等于:x &= y
// 位或等于:x |= y
// 位异或等于:x ^= y
// 位左移等于:x <<= n
// 位右移等于:x >>= n
// 位右移逻辑等于:x >>>= n
int num = 5;
num += 3; // num 现在是 8
num *= 2; // num 现在是 16
num /= 4; // num 现在是 4
num %= 3; // num 现在是 1
  • 图例

名称描述值类型示例DSL 规则
lhs二元表达式的左值literal类节点、valueAccess类节点、functionCall类节点int i = 1;binaryOperation bo where bo.lhs.name == “i”;
operator二元表达式的操作符字符串while (i == 1)binaryOperation bo where bo.operator == “==”;
rhs二元表达式的右值literal类节点、valueAccess类节点、functionCall类节点a > b;binaryOperation bo where bo.rhs.name == “b”;
operands二元表达的操作对象(左值和右值)节点集合a > b;binaryOperation bo where
  bo.operands contain op where
    op.name == “a”;

3.6. 条件表达式/三目运算(ternaryOperation)

条件表达式,也称为三目运算符(Ternary Operator),是一种简洁的条件语句,格式如下:

result = condition ? value_if_true : value_if_false;

这里的 condition 是一个布尔表达式,value_if_true 是当条件为 true 时的结果,而 value_if_false 是当条件为 false 时的结果。这个表达式的结果 result 将是两个值中的一个,取决于条件的真假。

  • 样例代码
// 基本使用
int a = 10;
int b = 20;
// max 将被赋值为 20,因为 20 大于 10
int max = (a > b) ? a : b; // 嵌套使用
int x = 5;
// result 将是 "x 大于 5"
String result = (x > 10) ? "x 大于 10" : ((x > 5) ? "x 大于 5" : "x 小于等于 5");// 与赋值结合
int score = 85;
// grade 将被赋值为 "B"
String grade = (score >= 90) ? "A" : ((score >= 80) ? "B" : "C");// 用于方法调用
// outcome 将随机是 "Heads" 或 "Tails"
String outcome = (Math.random() > 0.5) ? "Heads" : "Tails";// 与循环结合for (int i = 0; i < 10; i++) {// 将打印出 0, -1, 4, -3, 等等int value = (i % 2 == 0) ? i * i : -i;System.out.println(value);
}
  • 图例

名称描述值类型示例DSL 规则
condition判断条件binaryOperationboolean res = num > 1 ? true : false;ternaryOperation tp where
  tp.condition.lhs.name == “num”;
thenExpression真的操作任意节点boolean res = num > 1 ? true : false;ternaryOperation tp where
  tp.thenExpression contain literal ll where
    ll.value == true;
elseExpression假的操作任意节点String str = num > 1 ? “true” : “false”;ternaryOperation tp where
  tp.elseExpression contain literal ll where
    ll.value == “false”;

3.7. 方法引用表达式(methodReferenceExpression)

方法引用(Method References),它是一种快捷的Lambda表达式,允许你直接引用已有方法或构造函数。方法引用通常用于实现简单的函数式接口。

  • 样例代码
// 静态方法引用List<String> list = Arrays.asList("a", "b", "c");
// System.out::println 是一个方法引用,它引用了 System.out 对象的 println 静态方法。
list.forEach(System.out::println);// 实例方法引用
// 当Lambda体需要调用一个实例方法时,第一个参数将成为方法的调用者:List<String> list = Arrays.asList("hello", "world");
// String::toLowerCase 是一个方法引用,它引用了 String 类的 toLowerCase 实例方法。
String result = list.stream().map(String::toLowerCase).collect(Collectors.joining(" "));
// result 将是 "hello world"// 构造函数引用
// StringBuilder::new 是一个构造函数引用,它引用了 StringBuilder 类的构造函数。
Function<String, StringBuilder> constructor = StringBuilder::new;
StringBuilder sb = constructor.apply("Hello World");// 特定类的任意对象的实例方法引用
// 当Lambda的第一个参数是某个类的对象时,可以使用类名加 :: 加方法名的方式引用该类的实例方法:List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// upperCaseNames 包含了 "ALICE", "BOB", "CHARLIE"
List<String> upperCaseNames = names.stream().map(String::toUpperCase).collect(Collectors.toList());// 数组的实例方法引用
// 对于数组,可以使用数组类型加 ::new 来引用数组的构造方法:// String[]::new 是一个方法引用,它引用了 String[] 类型的构造方法。
Function<Integer, String[]> creator = String[]::new;
// 创建了一个长度为3的String数组
String[] strings = creator.apply(3);
  • 图例

名称描述值类型示例DSL 规则
name方法名字符串Supplier<Integer> size = list::size;methodReferenceExpression mf where
  mf.name == “size”;
function调用的方法functionDeclaration节点Supplier<Integer> size = list::size;methodReferenceExpression mf where
  mf.function.name == “size”;
type方法返回值类型objectType节点Supplier<Integer> size = list::size;methodReferenceExpression mf where
  mf.type.name == “int”;

3.8. lambda表达式(lambdaExpression)

Lambda 表达式是一种简洁的匿名函数表达式,允许你将行为作为参数传递给方法或存储在变量中。Lambda 表达式提供了一种非常灵活和强大的方式来处理函数式编程,使得代码更加简洁和表达性强。

  • 样例代码
// 基本 Lambda 表达式
// 这个 Lambda 表达式没有参数,执行的操作是打印 "Hello, World!"。
() -> System.out.println("Hello, World!");// 带参数的 Lambda 表达式
// 这个 Lambda 表达式接受两个参数 x 和 y,执行的操作是将它们相加。
(x, y) -> x + y// 使用 Lambda 表达式实现 Runnable
// 这里创建了一个 Runnable 实例,它将在调用 run 方法时执行 Lambda 表达式。
Runnable runnable = () -> System.out.println("I'm running on a thread!");
runnable.run();// 使用 Lambda 表达式排序集合
// 在这个例子中,Lambda 表达式实现了 Comparator 接口,用于按字典顺序排序字符串。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, (name1, name2) -> name1.compareTo(name2));// 使用 Lambda 表达式过滤集合
// 这里使用 Lambda 表达式创建了一个流,过滤出长度小于 5 的名字。
List<String> shortNames = names.stream().filter(name -> name.length() < 5).collect(Collectors.toList());// 输出集合中的单数
list.forEach(integer -> {if (integer % 2 == 1) {System.out.println("单数");}
});// 使用 Lambda 表达式转换集合
// 在这个例子中,Lambda 表达式用于将每个名字转换为其长度。
List<Integer> lengths = names.stream().map(name -> name.length()).collect(Collectors.toList());// 使用 Lambda 表达式实现简单的函数
// Lambda 表达式 name -> name.length() 实现了 Function 接口,用于返回字符串的长度。
Function<String, Integer> lengthFunction = name -> name.length();
int length = lengthFunction.apply("Hello");
// 使用 Lambda 表达式实现消费者
// Lambda 表达式 name -> System.out.println(name.toUpperCase()) 实现了 Consumer 接口,用于打印字符串的大写形式。
Consumer<String> consumer = name -> System.out.println(name.toUpperCase());
consumer.accept("Alice");// 使用 Lambda 表达式实现供应商
// Lambda 表达式 () -> "Hello, Lambda!" 实现了 Supplier 接口,用于提供字符串。
Supplier<String> supplier = () -> "Hello, Lambda!";
String message = supplier.get();
  • 图例

名称描述值类型示例DSL 规则
parameters参数paramDeclaration节点list.forEach(integer -> {
  if (integer == 1) {
    System.out.println(“单数”);
  }
});
lambdaExpression le where
  le.parameters contain p where p.name == “integer”;
body方法体block语句块list.forEach(integer -> {
  if (integer == 1) {
    System.out.println(“单数”);
  }
});
lambdaExpression le where
  le.body contain variableAccess va where va.name == “integer”;
body.statementNum语句数量数值list.forEach(integer -> {
  if (integer == 1) {
  System.out.println(“单数”);
  }
});
lambdaExpression le where
  le.body.statementNum == 1;
firstStatement第一条语句任意节点list.forEach(integer -> {
  if (integer == 2) {
    System.out.println(“单数”);
  }
});
lambdaExpression le where
  le.firstStatement contain ifBlock;
lastStatement最后一条语句任意节点list.forEach(integer -> {
  if (integer == 3) {
  System.out.println(“单数”);
  }
    System.out.print(“双数”);
  });
lambdaExpression le where
  le.lastStatement contain functionCall fc where
    fc.name == “print”;

3.9. 匿名内部类表达式(anonymousInnerClassExpression)

匿名内部类是当需要创建一个仅用于一次使用的类时使用的一种特殊类。它没有名称,并且通常是在声明的同时实例化。
匿名内部类提供了一种快速实现接口或继承类的方法,而无需定义一个具体的类名。这在创建一次性使用的类时非常有用,可以减少代码的冗余。

  • 样例代码

// 作为方法参数
// 调用方法时使用匿名内部类
// 假设有一个方法需要一个 List 作为参数,我们可以直接在调用时创建一个匿名内部类:
// 这里,我们创建了一个实现了 ArrayList 的匿名内部类,并在构造器中添加了元素。
process(new ArrayList<String>() {{add("Item 1");add("Item 2");}
});// 实现接口
// 在这个例子中,我们创建了一个实现了 Runnable 接口的匿名内部类,并重写了 run 方法。
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Hello from a thread!");}
}).start();
// 重写接口的多个方法// 使用 Comparator 进行排序
// 在这个例子中,我们创建了一个实现了 Comparator 接口的匿名内部类,用于按字典顺序比较字符串。
List<String> names = Arrays.asList("Bob", "Alice", "Eve");
Collections.sort(names, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}
});
// 如果需要实现一个接口并重写多个方法,也可以使用匿名内部类:
new SomeInterface() {@Overridepublic void method1() {// 实现细节}@Overridepublic void method2() {// 实现细节}
};
// 继承一个类
// 匿名内部类也可以继承一个类,并重写其方法:
// 在这个例子中,我们创建了一个继承自 SomeClass 的匿名内部类,并重写了 someMethod 方法。
new SomeClass() {@Overridepublic void someMethod() {// 重写方法}
};new MemberClass() {  // 告警行@Overridepublic void f() {int i = 0;System.out.println("aaaaa");}
}.f();
  • 图例

名称描述值类型示例DSL 规则
name名字字符串public static void main(String[] args) {
  new MemberClass() {
    @Override
    public void f() {
    }
  }.f();
}
anonymousInnerClassExpression ac where and(
  ac.name == “MemberClass”,
  ac.enclosingFunctionName == “main”
);
anonymousClassBody类代码块任意节点集合public static void main(String[] args) {
  new MemberClass() {
    @Override
    public void f() {
    }
  }.f();
}
anonymousInnerClassExpression ac where
  ac.anonymousClassBody ab contain functionDeclaration;

4. CodeNavi插件

  • 在Vscode 的插件中,查询:codenavi,并安装。

  • 使用插件的链接安装: https://marketplace.visualstudio.com/items?itemName=HuaweiCloud.codenavi

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/373413.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudAlibaba Nacos配置中心与服务发现

目录 1.配置 1.1配置的特点 只读 伴随应用的整个生命周期 多种加载方式 配置需要治理 1.2配置中心 2.Nacos简介 2.1特性 服务发现与服务健康检查 动态配置管理 动态DNS服务 服务和元数据管理 3.服务发现 1.配置 应用程序在启动和运行的时候往往需要读取一些配置信…

收银系统源代码-收银端UI风格

智慧新零售收银系统是一套线下线上一体化收银系统&#xff0c;给商户提供含线下收银称重、线上商城、精细化会员管理、ERP进销存、丰富营销活动、移动店务助手等一体化的解决方案。 如Windows版收银&#xff08;exe安装包&#xff09;、安卓版收银&#xff08;apk安装包&#…

HTML【详解】超链接 a 标签的四大功能(页面跳转、页内滚动【锚点】、页面刷新、文件下载)

超链接 a 标签主要有以下功能&#xff1a; 跳转到其他页面 <a href"https://www.baidu.com/" target"_blank" >百度</a>href&#xff1a;目标页面的 url 地址或同网站的其他页面地址&#xff0c;如 detail.htmltarget&#xff1a;打开目标页面…

关于【AI绘画】的学习

AI绘画中有个牛器DeepArt,也有很多AI软件和平台可以去借鉴和学习。 这里是一张AI绘画图片,主题是一个梦幻般的森林,里面充满了发光的蘑菇和飞舞的萤火虫: AI绘画资源 对于AI绘画,你可以参考一些在线平台和软件,它们提供了AI绘画的功能或者教程。此外,也可以寻找相关的书…

景芯SoC训练营DFT debug

景芯训练营VIP学员在实践课上遇到个DFT C1 violation&#xff0c;导致check_design_rule无法通过&#xff0c;具体报错如下&#xff1a; 遇到这个问题第一反映一定是确认时钟&#xff0c;于是小编让学员去排查add_clock是否指定了时钟&#xff0c;指定的时钟位置是否正确。 景芯…

神领物流项目第一天

文章目录 聚焦快递领域首先第一个是验证码模块流程登录接口权限管家 聚焦快递领域 首先第一个是验证码模块流程 首先生成验证码的流程 可以使用工具类去生成验证码 LineCaptcha lineCaptcha CaptchaUtil.createLineCaptcha(160, 60, 4, 26);// 获取值然后存入redis中 strin…

WPF引入多个控件库使用

目的 设计开发时有的控件库的一部分符合我们想要的UI样式&#xff0c;另一部分来自另一个控件库&#xff0c;想把两种库的样式做一个整合在同一个控件资源上。单纯通过引用的方式会导致原有样式被覆盖。这里通过设置全局样式的方式来实现。 1.安装控件库nuget包&#xff1a;H…

分享中国-吉林省和9个地级市州人文地图

分享中国-吉林省和9个地级市州人文地图 1、吉林省 吉林省&#xff0c;位于中国东北地区中部&#xff0c;地处东北亚地理中心位置&#xff0c;因吉林市而得名&#xff0c;清康熙时在松花江畔建吉林乌拉城&#xff0c;满语意为“沿江的地方”。 吉林省以中部大黑山为界&#x…

git为文件添加可执行权限

查看文件权限 git ls-files --stage .\SecretFinder.py100644 表示文件的所有者有读取和写入权限 添加可执行权限 git update-index --chmod x .\SecretFinder.py再次查看文件权限 git ls-files --stage .\SecretFinder.py100755 表示文件的所有者有读取、写入和执行权限

记录|C#安装+HslCommunication安装

记录线索 前言一、C#安装1.社区版下载2.VS2022界面设置 二、HslCommunication安装1.前提2.安装3.相关文件【重点】 更新记录 前言 初心是为了下次到新的电脑上安装VS2022做C#上机位项目时能快速安装成功。 一、C#安装 1.社区版下载 Step1. 直接点击VS2022&#xff0c;跳转下…

PostgreSQL 里怎样解决多租户数据隔离的性能问题?

文章目录 一、多租户数据隔离的性能问题分析&#xff08;一&#xff09;大规模数据存储和查询&#xff08;二&#xff09;并发访问和锁争用&#xff08;三&#xff09;索引维护成本高&#xff08;四&#xff09;资源分配不均 二、解决方案&#xff08;一&#xff09;数据分区&a…

【源码+方案】SRM供应商采购管理PPT(原件)

1、供应商管理流程 2、供应源搜寻 3、供应商评估 4、供应商选择 5、供应商考核评定 6、供应商关系管理 7、供应商开发 本文源码建设方案及软件全套资料获取&#xff1a;本文末个人名片直接获取或者进主页。

数据结构双向循环链表

主程序 #include "fun.h" int main(int argc, const char *argv[]) { double_p Hcreate_head(); insert_head(H,10); insert_head(H,20); insert_head(H,30); insert_head(H,40); insert_tail(H,50); show_link(H); del_tail(H); …

QT--SQLite

配置类相关的表&#xff0c;所以我使用sqlite,且QT自带该组件&#xff1b; 1.安装 sqlite-tools-win-x64-3460000、SQLiteExpert5.4.31.575 使用SQLiteExpert建好数据库.db文件&#xff0c;和对应的表后把db文件放在指定目录 ./db/program.db&#xff1b; 2.选择sql组件 3.新…

Qt 异步实现事件的定时执行 - QTimer和QThread的联合使用

异步实现事件的定时执行 - QTimer和QThread的联合使用 引言一、核心源码二、其信号和槽函数简述三、定时器及其moveToThread简述 引言 在 Qt 中&#xff0c;如果想要定时执行某些事件或函数&#xff0c;通常会使用 QTimer 类。QTimer 允许设置一个时间间隔&#xff0c;当这个时…

Linux镜像源设置不再难:一键脚本,新手也能成为优化高手(一键切换镜像源/Docker一键安装脚本)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 更换镜像源 📒📝 一键切换软件源📝 Docker一键安装脚本⚓️ 相关链接 ⚓️📖 介绍 📖 在国内,Linux系统用户经常会遇到下载软件包时速度慢的问题,这通常是因为默认的镜像源并不总是最优选择。对于新手来说,手动设置…

Spin Image(旋转图像)

Spin Image特征描述子原理 Spin Image是Johnson于1999年提出&#xff0c;Lazebnik于2005年完善的基于点云空间分布的特征描述方法&#xff0c;其思想是将一定区域的点云分布转换成二维的Spin Image&#xff0c;然后对场景和模型的Spin Image进行相似性度量。Spin Image方法与通…

HippoRAG如何从大脑获取线索以改进LLM检索

知识存储和检索正在成为大型语言模型(LLM)应用的重要组成部分。虽然检索增强生成(RAG)在该领域取得了巨大进步&#xff0c;但一些局限性仍然没有克服。 俄亥俄州立大学和斯坦福大学的研究团队推出了HippoRAG&#xff0c;这是一种创新性的检索框架&#xff0c;其设计理念源于人类…

CSDN回顾与前行:我的创作之旅——2048天的技术成长与感悟

CSDN回顾与前行&#xff1a;我的创作之旅——2048天的技术成长与感悟 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 前言 时光荏苒&#xff0c;岁月如梭。转眼间&#xff0c;从我在CSDN上写下第一篇技术博客《2-6 带头结点的链式表操作集…

腾讯又一平台即将停止运营

随着腾讯公司业务和战略的调整&#xff0c;某些业务逐渐退出历史舞台&#xff0c;如“腾讯直播平台NOW”&#xff0c;以及“QQ签到”&#xff0c;“腾讯待办”&#xff0c;“企鹅FM音频平台”等&#xff0c;最近又有一则重磅消息&#xff0c;那就是“腾讯课堂”也即将停止运营。…