Lua 第6部分 函数
在 Lua 语言中,函数( Function )是对语句和表达式进行抽象的主要方式。 函数既可以用
于完成某种特定任务(有时在其他语言中也称为过程 ( procedure )或子例程 ( s ubroutine) ),
也可以只是进行一些计算然后返回计算结果。 在前一种情况下,我们将一句函数调用视为一条语句 ;而在后一种情况下,我们则将函数调用视为表达式 :
print(8*9,9/8)
a=math.sin(3) + math.cos(10)
print(os.date())
无论哪种情况,函数调用时都需要使用一对圆括号把参数列表括起来。 即使被调用的函数不需要参数, 也需要一对空括号 () 。 对于这个规则,唯一的例外就是,当函数只有一个参数且该参数是字符串常量或表构造器时,括号是可选的:
print "Hello World" <--> print("Hello World")
dofile 'a.lua' <--> dofile(a.lua)
print [[a multi-line message]] <--> print([[a multi-line message]])
f{x=10, y=20} <--> f({x=10, y=20})
type{} <--> type({})
Lua 语言也为面向对象风格的调用( object-oriented call )提供了一种特殊的语法,即冒
号操作符。 形如 o:foo(x)的表达式意为调用对象 o 的 foo 方法。
一个 Lua 程序既可以调用 Lua 语言编写的函数, 也可以调用 C 语言( 或者宿主程序使用的其他任意语言)编写的函数。 一般来说,我们选择使用 C 语言编写的函数来实现对性能要求更高,或不容易直接通过 Lua 语言进行操作的操作系统机制等。 例如 , Lua 语言标准库中所有的函数就都是使用 C 语言编写的。 不过 ,无论一个函数是用 Lua 语言编写的还是用 C语言编写的 , 在调用它们时都没有任何区别 。
正如我们已经在其他示例中所看到的, Lua 语言中的函数定义的常见语法格式形如 :
-- 对序列'a'中的元素求和
function add (a)local sum = 0for i = 1, #a dosum = sum + a[i]endreturn sum
end
在这种语法中 ,一个函数定义具有一个函数名(name ,本例中的 add) 、 一个参数( parameter )
组成的列表和 由一组语句组成的函数体( body ) 。 参数的行为与局部变量的行为完全一致,相当于一个用函数调用时传入的值进行初始化的局部变量。
调用函数时使用的参数个数可以与定义函数时使用的参数个数不一致。 Lua 语言会通过抛弃多余参数和将不足的参数设为 nil 的方式来调整参数的个数。 例如 ,考虑如下的函数 :
> function f (a, b) print(a, b) end
> f()
nil nil
> f(3)
3 nil
> f(3,4)
3 4
> f(3,4,5)
3 4
虽然这种行为可能导致编程错误(在单元测试中容易发现),但同样又是有用的,尤其是对于默认参数 ( default argument ) 的情况。 例如 ,考虑如下递增全局计数器的函数 :
function incCount (n)n = n or 1globalCount = globalCount + n
end
该函数以 1 作为默认实参,当调用无参数的 incCount() 时,将 globalCounter 加 1 。 在调用
incCount() 时, Lua 语言首先把参数 n 初始化为 nil ,接下来的 or 表达式又返回了其第二个操作数,最终把 n 赋成了默认值 1 。
6.1 多返回值
Lua 语言中一种与众不同但又非常有用的特性是允许一个函数返回多个结果。 Lua 语言中几个预定义函数就会返回多个值。 我们已经接触过函数 string.find,该函数用于在字符串中定位模式。 当找到了对应的模式时,该函数会返回两个索引值 : 所匹配模式在字符串中起始字符和结尾字符的索引 。 使用多重赋值可以同时获取到这两个结果:
> s,e = string.find("hello Lua users", "Lua")
> print(s,e)
7 9
请记住,字符串的第一个字符的索引值为1。
Lua 语言编写的函数同样可以返回多个结果,只需在 return 关键字后列出所有要返回的值即可。 例如,一个用于查找序列中最大元素的函数可以同时返回最大值及该元素的位置:
function maximum( a )local mi = 1local m = a[mi]for i = 1, #a doif a[i] > m thenmi = i; m = a[i]endendreturn m, mi -- 返回最大值及其索引
end> print(maximum({8,10,23,12,4}))
23 3
Lua 语言根据函数的被调用情况调整返回值的数量。 当函数被作为一条单独语句调用时,其所有返回值都会被丢弃;当函数被作为表达式(例如,加法的操作数)调用时,将只保留函数的第一个返回值。 只有当函数调用是一系列表达式中的最后一个表达式(或是唯一一个表达式) 时 ,其所有的返回值才能被获取到 。 这里所谓的“一系列表达式”在 Lua 中表现为4 种情况 : 多重赋值、函数调用时传入的实参列表、表构造器和 return 语句 。 为了分别展示这几种情况,接下来举几个例子 :
function foo0 () end -- 不返回结果
function foo1 () return "a" end -- 返回1个结果
function foo2 () return "a", "b" end -- 返回2个结果
在多重赋值中,如果一个函数调用是一系列表达式中的最后(或者是唯一) 一个表达式, 则该函数调用将产生尽可能多的返回值以匹配待赋值变量 :
> x,y=foo2()
> print(x,y)
a b
> x=foo2()
> print(x)
a
> x,y,z=10,foo2()
> print(x,y,z)
10 a b
在多重赋值中,如果一个函数没有返回值或者返回值个数不够多,那么 Lua 语言会用 nil 来补充缺失的值 :
> x,y=foo0()
> print(x,y)
nil nil
> x,y=foo1()
> print(x,y)
a nil
> x,y,z=foo2()
> print(x,y,z)
a b nil
请注意,只有当函数调用是一系列表达式中的最后(或者是唯一 )一个表达式时才能返回多值结果,否则只能返回一个结果:
> x,y=foo2(),20
> print(x,y)
a 20 -- 'b' 被丢弃
> x,y=foo0(),20,30
> print(x,y)
nil 20 -- 30 被丢弃
当一个函数调用是另一个函数调用的最后一个(或者是唯一 )实参时 , 第一个函数的所有返回值都会被作为实参传给第二个函数。 我们已经见到过很多这样的代码结构,例如函数print 。 由于函数 print 能够接收可变数量的参数,所以 print (g())会打印出 g 返回的所有结果。
> print(foo0())> print(foo1())
a
> print(foo2())
a b
> print(foo2(), 1)
a 1
> print(foo2().."x")
ax
当在表达式中调用 foo2 时 , Lua 语言会把其返回值的个数调整为 1 。 因此 ,在上例的最后一行,只有第一个返回值” a ” 参与了字符串连接操作。
当我们调用 f(g() 时,如果 f 的参数是固定的,那么 Lua 语言会把 g 返回值的个数调整成与 f 的参数个数一致。 这并非巧合,实际上这正是多重赋值的逻辑。
表构造器会完整地接收函数调用的所有返回值 , 而不会调整返回值的个数:
t = {foo0()} -- t = {} (一个空表)
t = {foo1()} -- t = {"a"}
t = {foo2()} -- t = {"a", "b"}
不过,这种行为只有当函数调用是表达式列表中的最后一个时才有效 ,在其他位置上的函数调用总是只返回一个结果 :
> t={foo0(), foo2(),4}
> print(t[1],t[2],t[3])
nil a 4
最后,形如 return f() 的语句会返回 f 返回的所有结果 :
function foo (i)if i == 0 then return foo0()elseif i == 1 then return foo1()elseif i == 2 then return foo2()end
end> print(foo(1))
a
> print(foo(2))
a b
> print(foo(0))> print(foo(3))>
将函数调用用一对圆括号括起来可以强制其只返回一个结果:
> print((foo0()))
nil
> print((foo1()))
a
> print((foo2()))
a
应该意识到, return 语句后面的内容是不需要加括号的 , 如果加了括号会导致程序出现额外的行为 。 因此,无论 f 究竟返回几个值,形如 return (f(x))的语句只返回一个值。 有时这可能是我们所希望出现的情况,但有时又可能不是。
6.2 可变长参数函数
Lua 语言中的函数可以是可变长参数函数( variadic ) ,即可以支持数量可变的参数。 例如,我们已经使用一个、两个或更多个参数调用过函数 print。 虽然函数 print 是在 C 语言中定义的,但也可以在 Lua 语言中定义可变长参数函数。
下面是一个简单的示例,该函数返回所有参数的总和:
function add (...)local s = 0for _, v in ipairs{...} dos = s + v endreturn s
endprint(add(3,4,10,25,12))
参数列表中的三个点( ... )表示该函数的参数是可变长的。 当这个函数被调用时, Lua 内部会把它的所有参数收集起来,我们把这些被收集起来的参数称为函数的额外参数 。 当函数要访问这些参数时仍需用到三个点,但不同的是此时这三个点是作为一个表达式来使用的 。 在上例中,表达式 { ... }的结果是一个由所有可变长参数组成的列表,该函数会遍历该列表来累加其中的元素。
我们将三个点组成的表达式称为可变长参数表达式,其行为类似于一个具有多个返回值的函数,返回的是当前函数的所有可变长参数。 例如, print( ... ) 会打印出该函数的所有参数。 又如,如下的代码创建了两个局部变量 ,其值为前两个可选的参数(如果参数不存在则为 nil) :
local a, b = ...
实际上,可以通过变长参数来模拟 Lua 语言中普通的参数传递机制,例如 :
function foo (a, b, c)
可以写成:
function foo (...)local a, b, c = ...
喜欢 Perl 参数传递机制的人可能会更喜欢第二种形式。
形如下例的函数只是将调用它时所传人的所有参数简单地返回 :
function id (...) return ... end
该函数是一个多值恒等式函数 。 下列函数的行为则类似于直接调用函数 foo ,唯一不同之处是在调用函数 foo 之前会先打印出传递给函数 foo 的所有参数:
function foo1 (...)print("calling foo:", ...)return foo(...)
end
当跟踪对某个特定的函数调用时,这个技巧很有用 。
接下来再让我们看另外一个很有用的示例。 Lua 语言提供了专门用于格式化输出的函数
string.format 和输出文本的函数 io.write 。 我们会很自然地想到把这两个函数合并为一个具有可变长参数的函数 :
function fwrite (fmt, ...)return io.write(string.format(fmt, ...))
end
注意,在三个点前有一个固定的参数 fmt 。 具有可变长参数的函数也可以具有任意数量的固定参数,但固定参数必须放在变长参数之前。 Lua 语言会先将前面的参数赋给固定参数,然后将剩余的参数(如果有)作为可变长参数。
要遍历可变长参数,函数可以使用表达式 { ... } 将可变长参数放在一个表中,就像 add示例中所做的那样。 不过,在某些罕见的情况下,如果可变长参数中包含无效的 nil ,那么{ ... }获得的表可能不再是一个有效的序列 。 此时 ,就没有办法在表中判断原始参数究竟是不是以 nil 结尾的 。 对于这种情况, Lua 语言提供了函数 table.pack 。 该函数像表达式{ ... }一样保存所有的参数,然后将其放在一个表中返回,但是这个表还有一个保存了参数个数的额外字段 "n"。例如,下面的函数使用了函数 table.pack 来检测参数中是否有 nil:
function nonils (...)local arg = table.pack(...)for i = 1, arg.n doif arg[i] == nil then return false endendreturn true
end> print(nonils(2,3,nil))
false
> print(nonils(2,3))
true
> print(nonils())
true
> print(nonils(nil))
false
>
另一种遍历函数的可变长参数的方法是使用函数 select 。 函数 select 总是具有一个固定的参数 selector ,以及数量可变的参数。 如果 selector 是数值 n ,那么函数select 则返回第n 个参数后的所有参数 ; 否则 ,selector 应该是字符串 ”#” ,以便函数 select 返回额外参数的总数。
> print(select(1,"a","b","c"))
a b c
> print(select(2,"a","b","c"))
b c
> print(select(3,"a","b","c"))
c
> print(select("#","a","b","c"))
3
通常,我们在需要把返回值个数调整为 1 的地方使用函数 select ,因此可以把select(n, ... ) 认为是返回第 n 个额外参数的表达式。
来看一个使用函数 select 的典型示例,下面是使用该函数的 add 函数 :
function add (...)local s = 0for i = 1, select("#", ...) dos = s + select(i, ...)endreturn s
end
对于参数较少的情况,第二个版本的 add 更快,因为该版本避免了每次调用时创建一个新表。 不过,对于参数较多的情况,多次带有很多参数调用函数 select 会超过创建表的开销,因此第一个版本会更好(特别地,由于迭代的次数和每次迭代时传人参数的个数会随着参数的个数增长 ,因此第二个版本的时间开销是二次代价的)。
6.3 函数 table.unpack
多重返回值还涉及一个特殊的函数 table.unpack 。 该函数的参数是一个数组,返回值为数组内的所有元素:
> print(table.unpack{10,20,30})
10 20 30
> a,b = table.unpack{10,20,30}
> print(a,b)
10 20 -- 30 被丢弃
顾名思义,函数 table.unpack 与函数 table.pack 的功能相反。 pack 把参数列表转换成Lua语言中一个真实的列表( 一个表), 而 unpack 则把 Lua 语言中的真实的列表( 一个表)转换成一组返回值,进而可以作为另一个函数的参数被使用 。
unpack 函数的重要用途之一体现在泛型调用机制中 。 泛型调用机制允许我们动态地调用具有任意参数的任意函数。 例如,在 ISO C 中 ,我们无法编写泛型调用的代码,只能声明可变长参数的函数(使用 stdarg.h )或使用函数指针来调用不同的函数。 但是,我们仍然不能调用具有可变数量参数的函数,因为 C 语言中的每一个函数调用的实参个数是固定的 , 并且每个实参的类型也是固定的。 而在 Lua 语言中,却可以做到这一点 。 如果我们想通过数组 a 传人可变的参数来调用函数 f ,那么可以写成 :
f(table.unpack(a))
unpack 会返回 a 中所有的元素,而这些元素又被用作 f 的参数。 例如,考虑如下的代码 :
print(string.find("hello","ll"))
可以使用如下的代码动态地构造一个等价的调用 :
> f = string.find
> a = {"hello", "ll"}
>
> print(f(table.unpack(a)))
3 4
通常,函数 table.unpack 使用长度操作符获取返回值的个数,因而该函数只能用于序列 。 不过,如果有需要,也可以显式地限制返回元素的范围 :
> print(table.unpack({"Sun","Mon","Tue","Wed"},2,3))
Mon Tue
虽然预定义的函数 unpack 是用 C 语言编写的,但是也可以利用递归在 Lua 语言中实现 :
function unpack(t, i, n)i = i or 1n = n or #t if i <= n thenreturn t[i], unpack(t, t + 1, n)end
end
在第一次调用该函数时,只传入一个参数,此时 i 为 1 , n 为序列长度 ; 然后,函数返回 t[1]及 unpack(t, 2, n )返回的所有结果,而 unpack (t, 2, n ) 又会返回 t[2]及 unpack(t, 3, n )返回的所有结果,依此类推,直到处理完 n 个元素为止。
6.4 正确的尾调用
Lua 语言中有关函数的另一个有趣的特性是 , Lua 语言是支持尾调用消除的 。 这意味着Lua 语言可以正确地尾递归,虽然尾调用消除的概念并没有直接涉及递归。
尾调用是被当作函数调用使用的跳转。 当一个函数的最后一个动作是调用另一个函数而没有再进行其他工作时 ,就形成了尾调用 。 例如 ,下列代码中对函数 g 的调用就是尾调用 :
function f (x) x = x + 1; return g(x) end
当函数 f 调用完函数 g 之后, f 不再需要进行其他的工作。 这样,当被调用的函数执行结束后,程序就不再需要返回最初的调用者。 因此 ,在尾调用之后,程序也就不需要在调用栈中保存有关调用函数的任何信息 。 当 g 返回时,程序的执行路径会直接返回到调用 f 的位置。在一些语言的实现中,例如 Lua 语言解释器,就利用了这个特点,使得在进行尾调用时不使任何额外的栈空间 。 我们就将这种实现称为尾调用消除。
由于尾调用不会使用栈空间,所以一个程序中能够嵌套的尾调用的数量是无限的。 例如 ,
下列函数支持任意的数字作为参数 :
function foo (n)if n > 0 then return foo(n - 1) end
end
该函数永远不会发生栈溢出 。
关于尾调用消除的一个重点就是如何判断一个调用是尾调用 。 很多函数调用之所以不是尾调用,是由于这些函数在调用之后还进行了其他工作。 例如,下例中调用 g 就不是尾调用:
function f (x) g(x) end
这个示例的问题在于,当调用完 g 后, f 在返回前还不得不丢弃 g 返回的所有结果。 类似的,以下的所有调用也都不符合尾调用的定义:
return g(x) + 1 -- 必须进行加法
return x or g(x) -- 必须把返回值限制为1个
return (g(x)) -- 必须把返回值限制为1个
在 Lua 语言中,只有形如 return func(args)的调用才是尾调用。 不过,由于 Lua 语言会在调用前对 func 及其参数求值,所以 func 及其参数都可以是复杂的表达式。 例如,下面的例子就是尾调用 :
return x[i].foo(x[j] + a*b, i + j)
相关文章:
Lua 第6部分 函数
在 Lua 语言中,函数( Function )是对语句和表达式进行抽象的主要方式。 函数既可以用 于完成某种特定任务(有时在其他语言中也称为过程 ( procedure )或子例程 ( s ubroutine) ), 也可以只是进行…...
OpenCv高阶(五)——SIFT特征提取
目录 SIFT特征提取 一、原理核心步骤 1. 尺度空间极值检测 2. 关键点定位 3. 方向分配 4. 描述子生成 二、SIFT算法具有的特点 三、SIFT特征提取器的简单使用 1、特征检测器的创建 2、 检测图像中的关键点 3、绘制关键点 4、计算关键点描述符 四、SIFT 算法的优缺点…...
基于Spring MVC的客户端真实IP获取方案解析
文章目录 基于Spring MVC的客户端真实IP获取方案解析概述核心方法解析代码实现工作流程 IP获取优先级策略IP有效性验证异常处理与日志使用场景注意事项扩展建议 基于Spring MVC的客户端真实IP获取方案解析 概述 在Web应用开发中,准确获取客户端真实IP地址是常见的…...
JavaScript爬虫基础篇:HTTP 请求与响应
在互联网的世界里,数据无处不在。无论是新闻资讯、商品信息,还是社交媒体动态,这些数据都以各种形式存储在服务器上。而爬虫,就是我们获取这些数据的得力助手。今天,我们就来聊聊爬虫的基础——HTTP 请求与响应&#x…...
【Java基础】Java集合遍历方式
前言 在Java编程中,集合(Collection)是存储和操作对象的核心工具。遍历集合是开发者最频繁的操作之一,但不同场景下选择合适的遍历方式至关重要。 一、基础遍历方式 1. 基本for循环 适用场景:仅适用于List等有序集…...
KWDB创作者计划—深度解析:AIoT时代的分布式多模型数据库新标杆
在AIoT(人工智能物联网)快速发展的今天,数据的多样性、实时性和复杂性对数据库提出了前所未有的挑战。传统的数据库架构往往难以同时满足时间序列数据的高效处理、关系型数据的复杂查询以及多模型数据的无缝集成需求。而KWDB 2.2.0版本的发布…...
智慧城市大数据整体建设方案,数据中台方案(word)
第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章…...
Nginx:轻量级高性能的Web服务器与反向代理服务器
目录 一.引言 二.Nginx的核心特点 2.1高性能与高并发 2.2低资源消耗 2.3功能丰富 2.4高度扩展性 三.Nginx的应用场景 3.1静态资源服务器 3.2反向代理服务器 3.3API网关 3.4Nginx的配置与使用 四.总结 一.引言 在互联网高速发展的今天,Web服务器的性能与…...
【Pandas】pandas DataFrame pop
Pandas2.2 DataFrame Indexing, iteration 方法描述DataFrame.head([n])用于返回 DataFrame 的前几行DataFrame.at快速访问和修改 DataFrame 中单个值的方法DataFrame.iat快速访问和修改 DataFrame 中单个值的方法DataFrame.loc用于基于标签(行标签和列标签&#…...
Spring Boot集成MinIO的详细步骤
1. 安装MinIO 使用Docker部署MinIO 拉取MinIO镜像: docker pull minio/minio 这将从Docker Hub中获取最新的MinIO镜像。 创建目录: mkdir -p /home/minio/config mkdir -p /home/minio/data 这些目录将用于持久化MinIO的数据和配置文件 创建MinIO…...
【文献笔记】SatLM: Satisfiability-Aided Language Models Using Declarative Prompting
SatLM: Satisfiability-Aided Language Models Using Declarative Prompting 原文代码 标题翻译:SATLM:使用声明式提示的语言模型SAT辅助 1. 简介 1.1. 研究问题 文章提出了SATLM方式,使用LLM生成声明性任务规范,而不是命令式…...
LRU算法
package LRU缓存;import java.util.Arrays; import java.util.HashMap;//建立一个双向队列 class MyQueueNode{int key;int value;MyQueueNode pre;MyQueueNode next;public MyQueueNode(int key,int value){this.key key;this.valuevalue;} } class MyQueue{MyQueueNode head…...
二进制和docker两种方式部署Apache pulsar(standalone)
#作者:闫乾苓 文章目录 1、二进制安装部署Pulsar(standalone)1.1 安装配置JDK1.2 下载解压pulsar安装包1.3 启动独立模式的Pulsar 集群1.4 创建主题测试1.5 向主题写入消息测试1.6 从主题中读取消息测试 2.docker安装部署Pulsar(standalone)2.1 使用docker 启动Pul…...
【物联网】基于LORA组网的远程环境监测系统设计
基于LORA组网的远程环境监测系统设计 演示视频: 简介: 1.本系统有一个主机,两个从机。 2.一主多从的LORA组网通信,主机和两个从机都配备了STM32F103单片机与 LoRa 模块,主机作为中心设备及WIFI网关,负责接收和发送数据到远程物联网平台和手机APP,两个从机则负责采集数…...
k8s+有状态nacos账户密码安全认证开启+springcloud 配置
nacos 账号密码登录,默认未开启验证权限,不登录也能访问nacos控制台配置文件,生产环境非常不安全。所以需要手动开启安全认证。本地启动nacos的 application.properties配置文件更改如下: ### The auth system to use, currently only nacos …...
《分布式软总线赋能老旧设备高效通信》
在数字化转型的浪潮中,分布式软总线技术成为实现设备互联互通的关键力量。然而,当面对大量老旧设备时,其性能受限的现状对分布式软总线提出了严峻挑战。如何在这些性能瓶颈下,让老旧设备实现高效连接与通信,是亟待解决…...
07-云原生安全深度剖析:从 Kubernetes 集群防护到微服务安全加固
云原生安全深度剖析:从 Kubernetes 集群防护到微服务安全加固 一、云原生时代的安全挑战 1.1 云原生架构的复杂性引入新风险 在云原生架构下,Kubernetes 集群管理着大量动态变化的容器化应用,微服务通过 API 频繁交互,传统安全…...
Object.create(null)`和`{}`创建的对象有什么区别?
在 JavaScript 中,使用 Object.create(null) 和 {} 创建的对象有以下核心区别: 1. 原型链的差异 创建方式原型链([[Prototype]])继承关系const obj {}继承自 Object.prototype拥有 Object 的原型方法const obj Object.create(n…...
Sherpa简介
Sherpa 是一个由 K2-FSA 团队 开发的 开源语音处理框架,旨在解决传统语音识别工具(如 Kaldi)在模型部署和跨平台适配中的复杂性问题。它通过整合现代深度学习技术和高效推理引擎,提供了从语音识别、合成到说话人识别的一站式解决方…...
【MySQL】索引事务
索引 1.索引概念 数据库使用select查询需要将表中所有的数据都遍历一遍筛选出满足where条件的,如果表中数据非常多,遍历一遍就需要O(n)复杂度是非常高的,为此就引入了索引的概念。 索引是查询的优化手段,避免对表进行遍历&…...
STL详解 - list
目录 一、List容器概述 1.1 什么是list? 1.2 核心特点 二、List的定义与初始化 三、List 的基本操作 3.1 插入操作 🌵头插和尾插 🌵指定位置插入 3.2 删除操作 🍋头删和尾删 🍋指定位置删除 四、List 的迭代…...
LinkedList<Integer> 常用方法通俗讲解
LinkedList<Integer> linkedList new LinkedList<>(); 创建了一个整数类型的链表。链表就像一列火车,每节车厢(节点)都连接着下一节车厢。下面我用通俗易懂的方式讲解它的主要方法: 1. 添加元素 add(5) - 在链表末尾添加数字5,…...
[250416] GitHub Action 新升级,支持 Windows on Arm
目录 GitHub Actions 更新:Windows arm64 托管运行器现已推出公共预览版 GitHub Actions 更新:Windows arm64 托管运行器现已推出公共预览版 现在,GitHub 为公共代码仓库免费提供了基于 Windows arm64 架构的托管运行器(Hosted R…...
Spring Boot 整合 Redis 实现点赞功能:从基础到实践
在当今互联网应用开发中,点赞功能几乎成为了各类内容平台的标配。它不仅能增加用户与内容之间的互动,还能直观地反映内容的受欢迎程度。本文将详细介绍如何使用 Spring Boot 整合 Redis 来实现一个简单的文章点赞功能,让你轻松掌握这一实用技…...
深入解析布尔注入:原理、实战与防御
目录 一、布尔注入的原理与核心逻辑 二、布尔注入的实战步骤 三、关键函数与绕过技巧 四、实战案例:获取数据库名称 五、防御策略与最佳实践 六、总结 一、布尔注入的原理与核心逻辑 布尔注入(Boolean-Based Blind SQL Injection)是一种…...
1.2 使用RawInputSharp来取得键盘硬件信息以及虚拟码
RawInputSharp 是一个 C# 库,用于处理 Windows 的原始输入(Raw Input) API,它允许开发者直接访问键盘、鼠标等输入设备的底层数据。 本例介绍如何读取键盘的虚拟码以及键盘硬件信息。效果如下图: 示例中:开始是1键的按下与抬起&am…...
C++23 中的可选扩展浮点类型:std::float{16|32|64|128}_t 和 std::bfloat16_t
文章目录 1. 扩展浮点类型概述2. 如何使用这些类型3. 编译器支持4. 特性测试宏5. 类型转换和重载决议6. 标准库支持7. 应用场景8. 总结 C23 引入了可选的扩展浮点类型,包括 std::float16_t、 std::float32_t、 std::float64_t、 std::float128_t 和 std::bfloa…...
JVM 内存调优
内存调优 内存泄漏(Memory Leak)和内存溢出(Memory Overflow)是两种常见的内存管理问题,它们都可能导致程序执行不正常或系统性能下降,但它们的原因和表现有所不同。 内存泄漏 内存泄漏(Memo…...
数据结构(java)栈与队列
栈:(先进后出) 入栈: 1.普通栈一定要放、最小栈放的原则是: *如果最小栈是空的,那么放 *如果最小栈的栈顶元素没有当前的元素小,则放 2.如果要放的的元素小于等于最小栈栈顶元素可以放吗?放 出栈: 需要…...
医疗大模型落地方案:技术选型、部署策略与调优
医疗大模型的落地应用已成为推动医疗行业数字化转型的重要引擎。本文将从技术选型、部署策略和调优方案三大维度,系统性地解析医疗大模型落地的关键要素,为医疗机构提供可操作的落地指南。随着人工智能技术的快速发展,医疗大模型已在影像诊断…...
JVM:类加载子系统
一、类加载子系统概述 类加载子系统由多个类加载器组成,它们负责从文件系统或者网络中读取二进制形式的字节码(.class)文件,并将其加载进 JVM。字节码文件中关于类的定义、类中属性的定义、类中方法的定义以及类中方法的字节码等…...
独家!美团2025校招大数据题库
推荐阅读文章列表 2025最新大数据开发面试笔记V6.0——试读 我的大数据学习之路 面试聊数仓第一季 题库目录 Java 1.写一个多线程代码 2.写一个单例代码 3.LinkedBlockingQueue原理 4.模板设计模式 5.如何设计一个 生产者-消费者队列 6.堆内存和栈内存 7.ThreadLo…...
Angular 框架详解:从入门到进阶
Hi,我是布兰妮甜 !在当今快速发展的 Web 开发领域,Angular 作为 Google 主导的企业级前端框架,以其完整的解决方案、强大的类型系统和丰富的生态系统,成为构建大型复杂应用的首选。不同于其他渐进式框架,An…...
使用Vue 3与.NET 8.0通过SignalR实现实时通信,并结合JWT身份验证
实时通信是一个非常重要的功能。SignalR是一个强大的库,能够帮助我们轻松实现客户端和服务器之间的实时数据传输。本文将结合你的代码示例,向你展示如何使用Vue 3作为前端框架,ASP.NET Core作为后端框架,通过SignalR实现实时消息通…...
Harmonyos-Navigation路由跳转
Harmonyos-Navigation路由跳转 概述Navigation路由跳转模块内页面路由系统路由表测试页代码创建并配置路由表文件配置创建好的路由表文件跳转页面 自定义路由表 跨模块路由封装库模块路由跳转工具类 概述 Navigation是路由容器组件,一般作为首页的根容器࿰…...
《人工智能应用创新》5天出审稿意见!
期刊简介 《人工智能应用创新(Innovative Applications of AI)》 (ISSN:3078-2147)是由香港修墨信息工程研究院举办,经国际同行评审后收录的学术期刊。本刊共分三个栏目:综述分析、应用示范、前…...
Excel数据自动填充到Word自定义表格
上一份工作在一家国企做软件测试,需求变来变去(3天一小改,5天换版面),xmind要先整理一遍测试用例(版本迭代,该废的废,该加的加),完了细节在禅道里补充&#x…...
Spring Boot一次接口请求涉及的完整执行链路
Spring Boot一次接口请求涉及的完整执行链路 🔁 Spring 项目请求执行链路(简化视图) 客户端请求(浏览器、Postman)↓ Tomcat(Servlet 容器)↓ 【Listener 监听器】↓ 【Filter 过滤器】&#x…...
mapbox基础,加载视频到地图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️raster 栅格图层 api二、🍀加载视频到…...
Android动态化技术优化
Android动态化技术优化 一、WebView优化基础 1.1 WebView性能瓶颈 初始化耗时内存占用高页面加载慢白屏问题 1.2 WebView基本配置 class OptimizedWebView : WebView {init {// 开启硬件加速setLayerType(LAYER_TYPE_HARDWARE, null)// 配置WebSettingssettings.apply {//…...
Spring Boot 自定义定时任务组件深度解析:Quartz 集成与设计模式实战
一、组件设计目标 解决痛点: 简化 Quartz 原生 API 的复杂性统一任务调度管理(增删改查、日志、重试)与 Spring Boot 生态无缝整合 二、实现步骤详解 1. 组件初始化配置 1.1 初始化 Quartz 表结构 下载 SQL 脚本 🔗 官方表…...
Java Bean演进历程:从POJO到Spring Boot配置绑定
一、早期阶段:手动编写Java Bean 基本结构 私有属性:所有字段均为private,保证封装性。 公共构造方法:提供无参构造(JavaBean规范)或有参构造(POJO常见)。 Setter/Getter方法&…...
信息科技伦理与道德0:课程安排
1 课程安排 分组讨论的议题如下: 1.1 生成对抗网络(GAN) (1)GAN生成伪造人脸与身份冒用风险 算法原理: GAN通过生成器(Generator)和判别器(Discriminator)…...
STM32F103C8T6-基于FreeRTOS系统实现步进电机控制
引言 上一篇文章讲述了如何使用蓝牙连接stm32进行数据收发控制步进电机,这篇在之前的基础上通过移植操作系统(FreeRTOS或者其他的也可以,原理操作都类似)实现步进电机控制。 上篇博客指路:STM32蓝牙连接Android实现云…...
数字资产和交易解决方案
数字资产和交易解决方案 一、背景 (一)数字经济的蓬勃发展 随着信息技术的飞速发展,数字经济已成为全球经济增长的新引擎。数字资产作为数字经济的重要组成部分,其价值逐渐被人们所认识和重视。数字资产包括但不限于数字货币、…...
计算机网络 实验四 静态路由的配置与应用
一、实验目的 熟悉路由器的工作原理;熟悉静态路由的原理;熟悉华为网络模拟器的使用方法;掌握网络拓扑图的绘制;掌握路由器的配置。 二、实验设备 PC、华为模拟器ENSP。 三、实验步骤 知识准备:路由器和静态路由的…...
二进制求和 - 简单
************* C topic: 67. 二进制求和 - 力扣(LeetCode) ************* Give the topic an inspection. Too many works these days. And no spare time for code learning. However here I am gagin. This topic is an easy one and I want to pra…...
【C++】 —— 笔试刷题day_18
一、压缩字符串(一) 题目解析 题目给定一个字符str,让我们将这个字符串进行压缩; **压缩规则:**出现多次的字符压缩成字符数字;例如aaa压缩成a3。如果字符值出现一次,1不用写。 算法思路 这道题总的来说就非常简单了…...
LeetCode 热题 100_最长递增子序列(87_300_中等_C++)(动态规划)
LeetCode 热题 100_最长递增子序列(87_300) 题目描述:输入输出样例:题解:解题思路:思路一(动态规划): 代码实现代码实现(思路一(动态规划…...
asp-for等常用的HTML辅助标记?
在ASP.NET Core Razor Pages 和 MVC 中,除了asp-for之外,还有许多常用的 HTML 辅助标记,下面为你详细介绍: 表单与路由相关 asp-action 和 asp-controller 用途:这两个标记用于生成表单或链接的 URL,指定…...