Lua 第9部分 闭包
在 Lua 语言中,函数是严格遵循词法定界的第一类值。
“第一类值”意味着 Lua 语言中的函数与其他常见类型的值(例如数值和字符串)具有同等权限: 一个程序可以将某个函数保存到变量中(全局变量和局部变量均可)或表中,也可以将某个函数作为参数传递给其他函数,还可以将某个函数作为其他函数的返回值返回 。
“词法定界”意味着 Lua 语言中的函数可以访问包含其自身的外部函数中的变量( 也意味着 Lua 语言完全支持 Lambda 演算)。
上述两个特性联合起来为 Lua 语言带来了极大的灵活性。 例如,一个程序可以通过重新定义函数来增加新功能,也可以通过擦除函数来为不受信任的代码(例如通过网络接收到的代码)创建一个安全的运行时环境 。更重要的是,上述两个特性允许我们在 Lua 语言中使用很多函数式语言的强大编程技巧。 即使对函数式编程毫无兴趣 ,也不妨学习一下如何探索这些技巧,因为这些技巧可以使程序变得更加小巧和简单。
9.1 函数是第一类值
如前所述, Lua 语言中的函数是第一类值。 以下的示例演示了第一类值的含义:
a = {p = print} -- 'a.p'指向'print'函数
a.p("hello world") --> hello world
print = math.sin -- 'print'现在指向sine函数
a.p(print(1)) --> 0.8414709848079
math.sin = a.p -- 'sin'现在指向print函数
math.sin(10, 20) --> 10 20
如果函数也是值的话,那么是否有创建函数的表达式呢?答案是肯定的 。事实上,Lua语言中常见的函数定义方式如下 :
function foo(x) return 2*x end
就是所谓的语法糖( syntactic sugar ) 的例子,它只是下面这种写法的一种美化形式:
foo = function (x) return 2*x end
赋值语句右边的表达式( function (x) body end )就是函数构造器,与表构造器{}相似。因此 ,函数定义实际上就是创建类型为 “function ” 的值并把它赋值给一个变量的语句 。
请注意在 Lua 语言中,所有的函数都是匿名的( anonymous )。像其他所有的值一样,函数并没有名字。 当讨论函数名时,比如 print ,实际上指的是保存该函数的变量。 虽然我们通常会把函数赋值给全局变量 ,从而看似给函数起了一个名字, 但在很多场景下仍然会保留函数的匿名性。 下面来看几个例子。
表标准库提供了函数 table.sort ,该函数以一个表为参数并对其中的元素排序。 这种函数必须支持各种各样的排序方式 :升序或降序 、按数值顺序或按字母顺序、按表中的键等。函数 sort 并没有试图穷尽所有的排序方式,而是提供了一个可选的参数,也就是所谓的排序函数,排序函数接收两个参数并根据第一个元素是否应排在第二个元素之前返回不同的值。 例如,假设有一个如下所示的表:
network = {{name = "grauna", IP = "210.26.30.34"},{name = "arraial", IP = "210.26.30.23"},{name = "lua", IP = "210.26.23.12"},{name = "derain", IP = "210.26.23.20"},
}
如果想针对 name 宇段 、按字母顺序逆序对这个表排序 ,只需使用如下语句:
table.sort(network, function(a,b) return (a.name > b.name) end)
可见,匿名函数在这条语句中显示出了很好的便利性。
像函数 sort 这样以另一个函数为参数的函数,我们称之为高阶函数。 高阶函数是一种强大的编程机制 ,而利用匿名函数作为参数正是其灵活性的主要来源。 不过尽管如此,请记住高阶函数也并没有什么特殊的,它们只是 Lua 语言将函数作为第一类值处理所带来结果的直接体现。
为了进一步演示高阶函数的用法,让我们再来实现一个常见的高阶函数,即导数。 按照通常的定义,函数 f 的导数为 f ' (x) = (f (x + d) - f (x)) / d ,其中 d 趋向于无穷小 。 根据这个定义,可以用如下方式近似地计算导数:
function derivative (f, delta)delta = delta or 1e-4return function(x)return (f(x + delta) - f(x))/deltaend
end
对于指定的函数 f ,调用 derivative(f)将返回(近似地)其导数 ,也就是另一个函数 :
c = derivative(math.sin)
> print(math.cos(5.2), c(5.2))
0.46851667130038 0.46856084325086
> print(math.cos(10), c(10))
-0.83907152907645 -0.83904432662041
9.2 非全局函数
由于函数是一种“第一类值”,因此一个显而易见的结果就是:函数不仅可以被存储在全局变量中,还可以被存储在表字段和局部变量中 。
我们已经在前面的章节中见到过几个将函数存储在表字段中的示例,大部分 Lua 语言的库就采用了这种机制(例如 io.read 和 math.sin )。如果要在 Lua 语言中创建这种函数,只需将到目前为止我们所学到的知识结合起来 :
Lib = {}
Lib.foo = function(x,y) return x+y end
Lib.goo = function(x,y) return x-y endprint(Lib.foo(2,3), Lib.goo(2,3)) --> 5 -1
当然, 也可以使用表构造器:
Lib = {foo = function (x,y) return x+y endgoo = function (x,y) return x-y end
}
除此以外, Lua 语言还提供了另一种特殊的语法来定义这类函数:
Lib = {}
function Lib.foo (x,y) return x+y end
function Lib.goo (x,y) return x-y end
在表字段中存储函数是 Lua 语言中实现面向对象编程的关键要素 。
当把一个函数存储到局部变量时,就得到了一个局部函数 ,即一个被限定在指定作用域中使用的函数。 局部函数对于包( package )而言尤其有用 : 由于 Lua 语言将每个程序段作为一个函数处理,所以在一段程序中声明的函数就是局部函数,这些局部函数只在该程序段中可见。 词法定界保证了程序段中的其他函数可以使用这些局部函数。
对于这种局部函数的使用, Lua 语言提供了一种语法糖 :
local function f (params)-- body
end
在定义局部递归函数时,由于原来的方法不适用,所以有一点是极易出错的。 考虑如下的代码 :
local fact = function(n)if n == 0 then return 1else return n*fact(n-1) -- 有问题end
end
当 Lua 语言编译函数体中的 fact(n-1)调用时,局部的 fact 尚未定义。 因此,这个表达式会尝试调用全局的 fact 而非局部的 fact 。 我们可以通过先定义局部变量再定义函数的方式来解决这个问题 :
local factfact = function(n)if n == 0 then return 1else return n*fact(n-1)end
end
这样,函数内的 fact 指向的是局部变量。 尽管在定义函数时,这个局部变量的值尚未确定,但到了执行函数时, fact 肯定已经有了正确的赋值。
当 Lua 语言展开局部函数的语法糖时,使用的并不是之前的基本函数定义。 相反,形如
lcoal function foo (params) body end
的定义会被展开成
local foo; foo = function (params) body end
因此,使用这种语法来定义递归函数不会有问题。
当然,这个技巧对于间接递归函数是无效的 。 在间接递归的情况下,必须使用与明确的前向声明等价的形式:
local f -- “前向”声明local function g ()some code f() some code
endfunction f ()some code g() some code
end
请注意,不能在最后一个函数定义前加上 local 。 否则,Lua 语言会创建一个全新的局部变量 f , 从而使得先前声明的 f (函数 g 中使用的那个)变为未定义状态。
9.3 词法定界
当编写一个被其他函数 B 包含的函数 A 时,被包含的函数 A 可以访问包含其的函数 B的所有局部变量,我们将这种特性称为词法定界( lexical scoping )。 虽然这种可见性规则听上去很明确 ,但实际上并非如此。 词法定界外加嵌套的第一类值函数可以为编程语言提供强大的功能,但很多编程语言并不支持将这两者组合使用。
先看一个简单的例子。 假设有一个表,其中包含了学生的姓名和对应的成绩, 如果我们想基于分数对学生姓名排序,分数高者在前,那么可以使用如下的代码完成上述需求:
names = {"Peter", "Paul", "Marry"}
grades = {Marr = 10, Paul = 7, Peter = 8}
table.sort(names, function(n1, n2) return grades[n1] > grades[n2] -- 比较分数end)
现在,假设我们想创建一个函数来完成这个需求:
function sortbygrade (names, grades)table.sort( names, function (n1, n2)return grades[n1] > grades[n2] -- 比较分数end )
end
在后一个示例中,有趣的一点就在于传给函数 sort 的匿名函数可以访问 grades ,而 grades是包含匿名函数的外层函数 sortbygrade 的形参。 在该匿名函数中, grades 既不是全局变量也不是局部变量,而是我们所说的非局部变量(由于历史原因,在 Lua语言中非局部变量也被称为上值)。
这一点之所以如此有趣是因为,函数作为第一类值,能够逃逸出它们变量的原始定界范围 。 考虑如下的代码:
function newCounter ()local count = 0return function () -- 匿名函数count = count + 1return countend
endc1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
在上述代码中,匿名函数访问了一个非局部变量( count )并将其当作计数器。 然而,由于创建变量的函数(newCounter )己经返回,因此当我们调用匿名函数时,变量 count 似乎已经超出了作用范围。 但其实不然,由于闭包( closure )概念的存在,Lua 语言能够正确地应对这种情况。 简单地说,一个闭包就是一个函数外加能够使该函数正确访问非局部变量所需的其他机制 。 如果我们再次调用 newCounter ,那么一个新的局部变量 count 和一个新的闭包会被创建出来,这个新的闭包针对的是这个新变量:
c2 = newCounter()
print(c2()) --> 1
print(c1()) --> 3
print(c2()) --> 2
因此,c1 和 c2 是不同的闭包。它们建立在相同的函数之上,但是各自拥有局部变量count的独立实例。
从技术上讲, Lua 语言中只有闭包而没有函数。 函数本身只是闭包的一种原型。 不过尽管如此,只要不会引起混淆,我们就仍将使用术语“函数”来指代闭包。
闭包在许多场合中均是一种有价值的工具。正如我们之前已经见到过的,闭包在作为诸如sort 这样的高阶函数的参数时就非常有用 。 同样,闭包对于那些创建了其他函数的函数也很有用 ,例如我们之前的newCounter示例及求导数的示例;这种机制使得 Lua 程序能够综合运用函数式编程世界中多种精妙的编程技巧。另外,闭包对于回调函数来说也很有用 。 对于回调函数而言,一个典型的例子就是在传统 GUI 工具箱中创建按钮。 每个按钮通常都对应一个回调函数,当用户按下按钮时,完成不同的处理动作的回调函数就会被调用 。
例如,假设有一个具有 10 个类似按钮的数字计算器(每个按钮代表一个十进制数字),我们就可以使用如下的函数来创建这些按钮:
function digitButton (digit)return Button{ lable = tostring(digit),action = function ()add_to_display(digit)end}
end
在上述示例中,假设 Button 是一个创建新按钮的工具箱函数, label 是按钮的标签, action是当按钮按下时被调用的回调函数。 回调可能发生在函数 digitButton 早已执行完后,那时变量 digit 已经超出了作用范围,但闭包仍可以访问它 。
闭包在另一种很不一样的场景下也非常有用。 由于函数可以被保存在普通变量中,因此在Lua 语言中可以轻松地重新定义函数,甚至是预定义函数。这种机制也正是 Lua 语言灵活的原因之一。 通常,当重新定义一个函数的时候,我们需要在新的实现中调用原来的那个函数。 例如,假设要重新定义函数 sin 以使其参数以角度为单位而不是以弧度为单位。 那么这个新函数就可以先对参数进行转换,然后再调用原来的 sin 函数进行真正的计算。 代码可能形如:
local oldSin = math.sin
math.sin = function (x)return oldSin(x*(math.pi/180))
end
另一种更清晰一点的完成重新定义的写法是:
do local oldSin = math.sinlocal k = math.pi / 180math.sin = function(x)return oldSin(x * k)end
end
上述代码使用了 do 代码段来限制局部变量 oldSin 的作用范围;根据可见性规则,局部变量oldSin 只在这部分代码段中有效。 因此,只有新版本的函数 sin 才能访问原来的 sin 函数,其他部分的代码则访问不了 。
我们可以使用同样的技巧来创建安全的运行时环境,即所谓的沙盒。 当执行一些诸如从远程服务器上下载到的未受信任代码时,安全的运行时环境非常重要。例如,我们可以通过使用闭包重定义函数 io.open 来限制一个程序能够访问的文件 :
do local oldOpen = io.open local access_OK = function (filename, mode)check access endio.open = function (filename, mode)if access_OK(filename, mode) then return oldOpen(filename, mode)elsereturn nil, "access denied"endend
end
上述示例的巧妙之处在于,在经过重新定义后,一个程序就只能通过新的受限版本来调用原来未受限版本的 io.open 函数。 示例代码将原来不安全的版本保存为闭包的一个私有变量,该变量无法从外部访问 。 通过这一技巧,就可以在保证简洁性和灵活性的前提下在 Lua 语言本身上构建 Lua 沙盒。 相对于提供一套大而全的解决方案,Lua 语言提供的是一套“元机制”,借助这种机制可以根据特定的安全需求来裁剪具体的运行时环境。
9.4 小试函数式编程
再举一个函数式编程的具体示例 。在本节中我们要开发一个用来表示几何区域的简单系统。 我们的目标就是开发一个用来表示几何区域的系统,其中区域即为点的集合。我们希望能够利用该系统表示各种各样的图形,同时可以通过多种方式(旋转、变换、并集等)组合和修改这些图形。
为了实现这样的一个系统,首先需要找到表示这些图形的合理数据结构。 我们可以尝试着使用面向对象的方案,利用继承来抽象某些图形;或者,也可以直接利用特征函数来进行更高层次的抽象(集合 A 的特征函数 是指当且仅当 x 属于 A 时
成立)。鉴于一个几何区域就是点的集合,因此可以通过特征函数来表示一个区域,即可以提供一个点(作为参数)并根据点是否属于指定区域而返回真或假的函数来表示一个区域。
举例来说,下面的函数表示一个以点(1.0, 3.0)为圆心、半径 4.5 的圆盘(一个圆形区域):
function disk1 (x, y)return (x - 1.0)^2 + (y - 3.0)^2 <= 4.5^2
end
利用高阶函数和词法定界,可以很容易地定义一个根据指定的圆心和半径创建圆盘的工厂 :
function disk (cx, cy, r)return function (x, y)return (x - cx)^2 + (y - cy)^2 <= r^2end
end
形如 disk(1.0, 3.0, 4.5)的调用会创建一个与 disk1 等价的圆盘。
下面的函数创建了一个指定边界的轴对称矩形:
function rect (left, right, bottom, up)return function (x, y)return left <= x and x <= right and bottom <= y and y <= up end
end
按照类似的方式,可以定义函数以创建诸如三角形或非轴对称矩形等其他基本图形。每一种图形都具有完全独立的实现,所需的仅仅是一个正确的特征函数。
接下来让我们考虑一下如何改变和组合区域。我们可以很容易地创建任何区域的补集 :
function complement ( r )return function (x, y)return not r(x, y)end
end
并集、交集和差集也很简单,参见示例 9.1 。
示例 9.1 区域的并集、交集和差集
function union (r1, r2)return function ( x, y )return r1(x, y) or r2(x, y)end
endfunction intersection (r1, r2)return function ( x, y )return r1(x, y) and r2(x, y)end
endfunction difference (r1, r2)return function ( x, y )return r1(x, y) and not r2(x, y)end
end
以下函数按照指定的增量平移指定的区域:
function translate(r, dx, dy)return function (x, y)return r(x - dx, y - dy)end
end
为了使一个区域可视化,我们可以遍历每个像素进行视口测试;位于区域内的像素被绘制为黑色,而位于区域外的像素被绘制为白色。为了用简单的方式演示这个过程,我们接下来写一个函数来生成一个 PBM(可移植位图)格式的文件来绘制指定的区域。
PBM 文件的结构很简单(这种结构也同样极为高效,但是这里强调的是简单性)。 PBM文件的文本形式以字符串“P1 ”开头,接下来的一行是图片的宽和高(以像素为单位),然后是对应每一个像素、由1 和 0 组成的数字序列(黑为1,白为0,数字和数字之间由可选的空格分开),最后是 EOF 。 示例 9.2 中的函数 plot 创建了指定区域的 PBM 文件,并将虚拟绘图区域(-1, 1],[-1,1)映射到视口区域[1, M], [1, N]中 。
function plot (r, M, N)io.write("P1n", M, " ", N, "\n") -- 文件头for i = 1, N do -- 对于每一行local y = (N - i*2)/N for j = 1, M do -- 对于每一列local x = (j*2 - M)/Mio.write(r(x, y) and "1" or "0")endio.write("\n")end
end
为了让示例更加完整,以下的代码绘制了一个南半球所能看到的娥眉月:
c1 = disk(0, 0, 1)
plot(difference(c1, translate(c1, 0.3, 0)), 500, 500)
相关文章:
Lua 第9部分 闭包
在 Lua 语言中,函数是严格遵循词法定界的第一类值。 “第一类值”意味着 Lua 语言中的函数与其他常见类型的值(例如数值和字符串)具有同等权限: 一个程序可以将某个函数保存到变量中(全局变量和局部变量均可&a…...
【Linux】冯诺依曼体系结构及操作系统架构图的具体剖析
目录 一、冯诺依曼体系结构 1、结构图 2、结构图介绍: 3、冯诺依曼体系的数据流动介绍 4、为什么在该体系结构中要存在内存? 二、操作系统架构图介绍 1、操作系统架构图 2、解析操作系统架构图 3、为什么要有操作系统? 前些天发现了一…...
解析虚拟机与Docker容器化服务的本质差异及Docker核心价值
解析虚拟机与Docker容器化服务的本质差异及Docker核心价值 1.1 硬件虚拟化与操作系统级虚拟化 虚拟机(VM)基于硬件级虚拟化技术(Hypervisor),通过模拟完整硬件栈(CPU、内存、存储、网络)创建独…...
FreeRTOS深度解析:队列集(Queue Sets)的原理与应用
FreeRTOS深度解析:队列集(Queue Sets)的原理与应用 什么是队列集? 在FreeRTOS中,队列集(Queue Sets,英文名xQueueSet)是一种强大的数据结构,用于高效管理多个队列。它的…...
java将pdf转换成word
1、jar包准备 在项目中新增lib目录,并将如下两个文件放入lib目录下 aspose-words-15.8.0-jdk16.jar aspose-pdf-22.9.jar 2、pom.xml配置 <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><versi…...
网络原理 - 6
目录 4. 滑动窗口 滑动窗口出现丢包 情况一:数据报已经抵达,ACK 被丢了编辑 情况二:数据报直接就丢了 5. 流量控制 完! 4. 滑动窗口 这个滑动窗口是 TCP 中非常有特点的机制。 我们知道,TCP 是通过确认应答&…...
【Linux网络】构建类似XShell功能的TCP服务器
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
Spring AI - Redis缓存对话
先看效果 对话过程被缓存到了Redis 中。 原理 在上一节我们快速入门了SpringAI,具体文章请查看:快速入门Spring AI 创建 ChatClient 的代码如下: this.chatClient ChatClient.builder(chatModel).defaultSystem(DEFAULT_PROMPT).defaultAd…...
rk3588 驱动开发(二)第四章嵌入式 Linux LED 驱动开发实验
4.1 Linux 下 LED 灯驱动原理 Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器。所以本章的 LED 灯驱动 最终也是对 RK3588 的 IO 口进行配置,与裸机实验不同的是,在 Linux 下编写驱动要符合 Linux 的驱动框架。开发板上的 LED 连接…...
第49讲:AI驱动的农业碳汇估算与生态价值评估 —— 打造更“绿”的智慧农业未来
目录 🌍 一、农业碳汇:我们为什么要关心它? 🤖 二、AI是如何介入农业碳汇评估的? 🛠 三、案例实战:AI估算区域农田碳汇储量 📍 场景设定: 📊 数据来源: 🔁 处理流程: 📈 四、生态价值评估:从碳储量到生态效益 🧭 五、平台与工具推荐 💬 六、…...
springmvc入门案例
目录 前言 springmvc概述 springmvc入门案例(使用配置类替代原本的web.xml) 第一步、创建一个web工程 第二步、引入相应的依赖(servlet-api、spring-webmvc、) 第三步、编写 SpringMVC配置类,并开启包扫描功能 第四步、编写…...
Node.js学习
概述 Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境,允许在服务器端运行 JavaScript 代码。它采用事件驱动和非阻塞 I/O 模型,适合构建高性能、可扩展的网络应用,尤其擅长处理实时应用和大规模数据密集型场景 背景 JavaScri…...
SQL注入漏洞中会使用到的函数
目录 一、信息获取函数 1. 通用函数 2. 元数据查询(INFORMATION_SCHEMA) 二、字符串操作函数 1. 字符串连接 2. 字符串截取 3. 编码/解码 三、报错注入专用函数 1. MySQL 2. SQL Server 3. PostgreSQL 四、时间盲注函数 1. 通用延迟 2. 计…...
MIT IDSS深度解析:跨学科融合与系统科学实践
麻省理工学院的IDSS(Institute for Data, Systems, and Society, IDSS)是一个致力于通过先进分析方法推动教育与研究的前沿机构。它将工程学、信息科学和数据科学的方法与社会科学的分析方法相结合,以应对复杂的社会挑战。 MIT IDSS 建立在统计学、计算机科学和特定应用领域…...
重塑智慧出行新生态,德赛西威全新战略愿景发布
4月22日,上海车展开幕前夕,德赛西威以“智新境,向远大”为主题,正式对外发布全新发展战略及使命、愿景;同时,代表未来AI出行趋势的智慧出行解决方案Smart Solution 3.0重磅亮相。 一、把握变革节点 创领产…...
全面解析 classification_report:评估分类模型性能的利器
解读 classification_report 的使用:评估分类模型性能的关键工具 在机器学习中,分类任务是最常见的应用场景之一。无论是垃圾邮件过滤、图像识别还是情感分析,分类模型的性能评估都是至关重要的一步。而 classification_report 是 Scikit-le…...
Qt案例 使用QFtpServerLib开源库实现Qt软件搭建FTP服务器,使用QFTP模块访问FTP服务器
本以为搭建和访问FTP服务器的功能已经是被淘汰的技术了,只会在学习新技术的时候才会了解学习学习,WinFrom版本,和windows Api版本访问FTP服务器的功能示例也都写过。没想到这次会在项目中再次遇到, 这里记录下使用Qt开源库QFtpSer…...
图像后处理记录
图像后处理记录 ocr后处理记录 opencv裁剪 编译命令 cmake -S . -B build-x64 -DBUILD_LIST"core,imgproc,imgcodecs,highgui" -DBUILD_SHARED_LIBSOFF -DBUILD_opencv_appsOFF -DBUILD_opencv_jsOFF -DBUILD_ANDROID_PROJECTSOFF -DBUILD_ANDROID_EXAMPLESOFF -…...
解决element中的el-anchor链接被作为路由跳转导致页面404
解决element中的el-anchor链接被作为路由跳转导致页面404 问题: 在使用elementPlus时,el-anchor-link中的href被识别为路由进行跳转,导致不能正常跳转到锚点,且页面显示404。 解决:自定义方法解决 <!--添加hand…...
Mapreduce中maven打包
MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。 MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序(例如:jar包),并发运行在…...
C++初阶——string的使用(下)
C初阶——string的使用(下) 一、string类对象的容量操作 对于string的容量操作,我们可以通过顺序表来理解,顺序表是通过动态数组来实现的,在数据结构专栏的第一篇就是顺序表的详细讲解,链接如下ÿ…...
AIGC vs 人类创作者:是竞争还是协作?
AIGC vs 人类创作者:是竞争还是协作? 随着人工智能技术的飞速发展,特别是生成式AI(AIGC, AI-Generated Content)的崛起,越来越多的领域开始出现AI的身影。从文本创作、图像生成到音乐制作,AIGC…...
Stable Baselines3 结合 gym 训练 CartPole 倒立摆
视频讲解: Stable Baselines3 结合 gym 训练 CartPole 倒立摆 今天介绍下stable_baselines3和gym,可以方便实现DL的实现,应用在机械臂catch、reach等场景 测试代码仓库:https://github.com/LitchiCheng/DRL-learning.git https:…...
ctfshow web8
前言 学习内容:简单的盲注脚本的书写 web8 这个题目题目手动注入很麻烦 主要是他过滤了 union 空格和 过滤了union的解决方法 1、使用盲注(报错注入和盲注) 2、使用时间盲注 3、堆叠注入 盲注脚本的书写 首先他是有注入点的 然后熟悉requests包的使用 …...
Linux程序地址空间
目录 研究背景 程序地址空间回顾 来段代码感受一下 进程地址空间 Linux2.6内核进程调度队列 一个CPU拥有一个runqueue 优先级 活跃队列(只出不进) 过期队列(只进不出) active指针和expired指针 总结 研究背景 Linux内核版本&#…...
破茧成蝶:阿里云应用服务器让传统 J2EE 应用无缝升级 AI 原生时代
丝滑升级拥抱大模型:详解AI时代的应用智能化升级路径 破茧成蝶:阿里云应用服务器让传统 J2EE 应用无缝升级AI原生时代 ——十年代码无需重写,三步开启智能化跃迁 作者:孤弋、孚阳 序幕:一场跨越 20 年的技术对话 在杭…...
游戏引擎学习第240天:将渲染器移至第三层
这节又枯燥又无聊简直了 回顾并为今天的内容做铺垫 昨天我们说到,想对渲染器和平台层的集成方式做一些修改。我们之前简单讲了一下修改的目的:我们希望游戏本身不再直接调用 OpenGL 的渲染代码,而是只生成一组渲染指令缓冲区,然…...
2025.04.23华为机考第三题-300分
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 时空旅行者的最优路径 问题描述 A先生是一名时空旅行者,他可以在不同的时空点之间穿梭。每次从一个时空点跳跃到另一个时空点需要消耗一个时间单位。在每个时空点,都有一些特…...
Kafka 保证多分区的全局顺序性的设计方案和具体实现
Kafka 本身无法直接保证多分区的全局顺序性,因为分区设计旨在并行处理以提升吞吐量。 要实现多分区的顺序性,可尝试通过以下方法在系统层面或业务逻辑上解决: 一、方案设计 单一分区路由(还是将消息发送到同一分区)&a…...
数据结构初阶:二叉树(四)
概述:本篇博客主要介绍链式结构二叉树的实现。 目录 1.实现链式结构二叉树 1.1 二叉树的头文件(tree.h) 1.2 创建二叉树 1.3 前中后序遍历 1.3.1 遍历规则 1.3.1.1 前序遍历代码实现 1.3.1.2 中序遍历代码实现 1.3.1.3 后序遍历代…...
华为开发岗暑期实习笔试(2025年4月16日)
刷题小记: 第一题怀疑测试样例不完整,贪心法不应该能够解决该题。第二题使用0-1BFS解决单源最短路径的问题,往往搭配双端队列实现。第三题是运用动态规划解决最大不重叠子区间个数的问题,难点在于满足3重判断规则,所需…...
第一篇:Django简介
第一篇:Django简介 文章目录 第一篇:Django简介一、纯手写一个简易版的web框架1、软件开发架构2、HTTP协议3、简易的socket服务端4、wsgiref模块5、动静态网页6、后端获取当前时间展示到html页面上7、字典数据传给html文件8、数据从数据库中获取的展示到…...
2025年渗透测试面试题总结-拷打题库13(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库13 一、GitHub等三方敏感信息泄漏防御 二、业务逻辑漏洞技术规避 …...
(09)Vue脚手架的使用(Vite、vue-cli、create-vue)
本系列教程目录:Vue3Element Plus全套学习笔记-目录大纲 文章目录 第3章 Vue脚手架3.1 vite3.3.1 Vite使用1)创建Vite项目2)Vite项目打包 3.1.2 组件化开发3.1.4 Vite工程运行原理1)分析main.js2)自定义根组件 3.2 vue…...
Unity 将Excel表格中的数据导入到Mysql数据表中
1.Mysql数据表users如下: 2.即将导入的Excel表格如下: 3.代码如下: using System; using System.Data; using System.IO; using Excel; using MySql.Data.MySqlClient; using UnityEngine; using UnityEditor;public class ImportExcel {// …...
【QT】信号与槽中多个按钮(pushbutton)共用一个槽函数的两种实现方式
两种方法的对比 方法1:sender() 优点:代码简洁,无需额外参数 缺点:依赖运行时类型转换,安全性较低 适用场景:简单场景,少量按钮 方法2:Lambda (推荐) 优点:安全直观&…...
Python----深度学习(神经网络的过拟合解决方案)
一、正则化 1.1、正则化 正则化是一种用于控制模型复杂度的技术。它通过在损失函数中添加额外的项(正则 化项)来降低模型的复杂度,以防止过拟合。 在机器学习中,模型的目标是在训练数据上获得较好的拟合效果。然而,过…...
【金仓数据库征文】从 HTAP 到 AI 加速,KingbaseES 的未来之路
国产数据库早已实现 “可替代”,但要真正与国际头部厂商掰手腕,必须在 HTAP(Hybrid‑Transaction/Analytical Processing)与 AI 加速 两条技术赛道上实现跨越。KingbaseES 自 V8R3 调整为多进程架构后,历经 V8R6、KSOn…...
创建第一个Spring Boot项目
什么是Spring Boot 随着Spring的快速发展,项目中的XML文件越来越多,繁琐的配置以及,整合第三方框架的配置问题,导致大大增加了开发和部署的效率,使开发者无法专心于业务的开发。Spring Boot就相当于使Spring框架的脚手…...
Java—— 正则表达式 练习
需求: 请编写正则表达式验证用户输入的手机号码是否满足要求。 请编写正则表达式验证用户输入的邮箱号是否满足要求。 请编写正则表达式验证用户输入的电话号码是否满足要求。 验证手机号码 13112345678 13712345667 13945679027 139456790271 验证座机电话号码 02…...
Linux[指令与权限]
Linux指令与权限 Linux环境中,打包文件有多种 tar (打包/解包) 指令 tar -czvf 文件要打包到的位置 文件(打包并压缩到) tar -xzvf 文件(在当前目录下解压) tar选项 -c创建压缩文件 -z使用gzip属性压缩 -v展现压缩过程 -f后面使用新建文档名 -x不要新建,解压 -C 文件…...
MySQL数据库精研之旅第十期:打造高效联合查询的实战宝典
专栏:MySQL数据库成长记 个人主页:手握风云 目录 一、简介 1.1. 为什么要使用联合查询 1.2. 多表联合查询时的计算 1.3. 示例 二、内连接 2.1. 语法 2.2. 示例 三、外连接 4.1. 语法 4.2. 示例 一、简介 1.1. 为什么要使用联合查询 一次查询需…...
【Redis】集合类型Set 常用命令详解
1. sadd - 添加 语法:sadd key value > sadd testset A 1 > sadd testset B 1 > sadd testset C 1 > sadd testset C # set的值不能重复 0 > smembers set1 # 查询指定set的所有值,乱序 1) "B" 2) "A" 3) "C&qu…...
React 5 种组件提取思路与实践
在开发时,经常遇到一些高度重复但略有差异的 UI 模式,此时我们当然会把组件提取出去,但是组件提取的方式有很多,怎么根据不同场景选取合适的方式呢?尤其时在复杂的业务场景中,组件提取的思路影响着着代码的可维护性、可读性以及扩展性。本文将以一个[详情]组件为例,探讨…...
第十五届蓝桥杯 2024 C/C++组 合法密码
目录 题目: 题目描述: 题目链接: 思路: substr函数: 思路详解: 代码: 代码详解; 题目: 题目描述: 题目链接: P10906 [蓝桥杯 2024 国 B] 合法密码 -…...
云原生时代的双轮驱动
在当今数字化浪潮汹涌澎湃的时代,企业 IT 主管、CIO、CTO 们肩负着引领企业乘风破浪、实现数字化转型的重任。而主数据平台与数据中台,宛如企业数字化征程中的双引擎,为企业发展注入强劲动力。 一、主数据与数据中台:企业数据世界…...
GD32F407单片机开发入门(六)定时器TIMER详解及实战含源码
文章目录 一.概要二.通用定时器内部结构1.时基单元2.时钟源3.输入捕获4.输出比较 三.通用定时器内部特色四.TIME定时器1ms中断例程五.工程源代码下载六.小结 一.概要 定时器就是计数器,应用在我们生活的方方面面,比如有闹钟、计时器等。在GD32F407VET6定…...
时序数据库 TDengine 助力石油石化业务, 平滑接替 Oracle 数据库
小T导读:胜软科技在石油石化行业中选择使用 TDengine 处理时序数据,不仅显著降低了运维数据库的成本,也大幅减少了存储空间的占用,实现了从原有的 40 多套 Oracle 数据库向仅 9 套 TDengine集群的精简替换。在迁移过程中ÿ…...
【问题解决】本机navicat连接云服务器mysql
一般情况下,当你使用navicat等工具连接云服务器会因为mysql的安全机制,导致无法连接root用户,但是在测试环境中,不考虑安全性的前提条件下,可以通过修改MySQL的配置文件来连接云服务器mysql的root用户。 选择数据库&am…...
STM32F407 的通用定时器与串口配置深度解析
在 STM32F407 芯片的开发过程中,通用定时器和串口的配置与使用是极为关键的技能点。本文将结合提供的代码示例,深入剖析这两个模块的配置流程、工作原理以及实际应用,助力开发者更好地掌握相关技术。 一、通用定时器 (一&#x…...