Lua 位和字节

news2024/11/24 18:56:51

一、位运算

从 Lua 5.3 版本开始,提供了针对数值类型的一组标准位运算符,与算数运算符不同的是,运算符只能用于整型数。

运算符描述
&按位与
|按位或
按位异或
>>逻辑右移
<<逻辑左移
~(一元运算)按位取反

位的使用,可以参考小盆友的另一篇文章 《android位运算简单讲解》
https://blog.csdn.net/weixin_37625173/article/details/83796580

print(string.format("%x", 0xff & 0xabcd))       --> cd
print(string.format("%x", 0xff | 0xabcd))       --> abff
print(string.format("%x", 0xff ~ 0xabcd))       --> ab32
print(string.format("%x", ~0))                  --> ffffffffffffffff (16 个 6,每一个十六进制 4 位,刚好是 64 位)
print(string.format("%x", 0xff << 12))          --> ff000
print(string.format("%x", 0xff >> -12))         --> ff000
-- 移位数等于或大于整型表示的位数,由于所有的位都被移出,则结果为 0
print(string.format("%x", -1 << 80))            --> 0

1-1、注意小点

所有的位运算针对一个整数型的所有位。

Lua 的两个移位操作都会用 0 填充空出的位,这种行为称为逻辑移位。 Lua 中没有提供算术右移(即使用符号位填充空出的位),但是可以通过向下取整除法( floor 除法)达到算数右移

local data = -0x100
print("逻辑右移:", string.format("%x >> 1 --> %x", data, data >> 1))    --> 逻辑右移:	ffffffffffffff00 >> 1 --> 7fffffffffffff80
-- 达到算数右移一位,2^n ( n 即为右移位数)
print("算数右移:", string.format("%x >> 1 --> %x", data, data // 2))    --> 算数右移:	ffffffffffffff00 >> 1 --> ffffffffffffff80

移位数是负数则表示向相反方向移位。a>>na<<-n 相等。

二、无符号整型数

在有符号整型数中使用一个比特位来存储符号位。所以 64 的整型数中最大可以表示为 2^63-1 ,而不是 2^64-1 。

值得注意的是 Lua 语言不显示支持无符号整型数, 但这并不妨碍我们在 Lua 中使用无符号整型这一特性,只是在使用过程中需要注意一些细节。

2-1、细节一:打印无符号整数

对于一个数最直观的就是展示出来,所以我们可以使用 string.format 进行格式化数值, 使用 %u(无符号整数)或 %X (十六进制)进行展示,这样就能很直观的感知无符号整数每一位的数值是多少。如果直接将无符号整数打印,会被认为是有符号整数,就不利于阅读。

local x = 3 << 62
print("有符号整数显示:", x)        --> 有符号整数显示:	-4611686018427387904
print("使用十进制无符号显示", string.format("%u", x))       --> 使用十进制无符号显示	13835058055282163712
print("使用十六进制无符号显示", string.format("0x%X", x))   --> 使用十六进制无符号显示	0xC000000000000000

2-2、细节二:无符号整数,加减乘运算

对于无符号整数的加减乘运算,和有符号是一样的,只是要注意溢出

local x = 3 << 62
print("使用十进制无符号显示", string.format("%u", x))                   --> 使用十进制无符号显示	13835058055282163712
print("使用十进制无符号显示 +1", string.format("%u", x + 1))            --> 使用十进制无符号显示 +1	13835058055282163713
print("使用十进制无符号显示 -1", string.format("%u", x - 1))            --> 使用十进制无符号显示 -1	13835058055282163711
x = 1 << 62
print("使用十六进制无符号显示", string.format("0x%X", x))               --> 使用十六进制无符号显示	    0x4000000000000000
print("使用十进制无符号显示 * 2", string.format("%X", x * 2))           --> 使用十进制无符号显示 * 2	0x8000000000000000

2-3、细节三:无符号整数,除法运算

对于无符号整数的除法会有些不一样,需要注意其符号位的影响,可以通过下面函数进行无符号整数的除法(细节也在每一行的注释中)

function udiv(n, d)
    -- d<0 实质比较除数是否大于 2^63
    if d < 0 then
        -- 如果除数大于被除数(n<d),则商为 0 ;否则为 1
        if math.ult(n, d) then
            return 0
        else
            return 1
        end
    end

    -- n >> 1 等价于将无符号整数 n / 2 , 这样的做法是先去除符号位置的影响
    -- 最后 << 1 等价于 * 2 ,这样是为了纠正一开始 >> 1
    -- // d 进行有符号整数的正常向下取整除法
    local q = ((n >> 1) // d) << 1
    -- 计算因为移位和向下取整导致的丢失数值,计算出两个结果后,如果偏差大于除数,说明需要加一
    local r = n - q * d
    if not math.ult(r, d) then
        q = q + 1
    end
    return q
end

local u1 = 1 << 1
-- 正常数字除法
local div1 = 2
print(string.format("%X/%X = %X", u1, div1, udiv(u1, div1)))        --> 2/2 = 1
-- (符号位为 1 )很大的数进行无符号除法
local u2 = 1 << 63
print(string.format("%X/%X = %X", u2, div1, udiv(u2, div1)))        --> 8000000000000000/2 = 4000000000000000 
-- (符号位为 0 )正常的数进行无符号除法
local u3 = 1 << 62
print(string.format("%X/%X = %X", u3, div1, udiv(u3, div1)))        --> 4000000000000000/2 = 2000000000000000
-- 除数很大,符号为为 1 ,被除数 < 除数
local div2 = 1 << 63
print(string.format("%X/%X = %X", u3, div2, udiv(u3, div2)))        --> 4000000000000000/8000000000000000 = 0
-- 被除数 > 除数
local u4 = (1 << 63) + 1
print(string.format("%X/%X = %X", u4, div2, udiv(u4, div2)))        --> 8000000000000001/8000000000000000 = 1
local u5 = (1 << 63) + 3
print(string.format("%X/%X = %X", u5, div1, udiv(u5, div1)))        --> 8000000000000003/2 = 4000000000000001

2-4、细节四:无符号整数比较

如果直接将无符号整数进行比较,则会导致一种情况:因为第 64 位在有符号整数是符号位,而无符号整数则用于正常表示数值,所以当第 64 位为 1 时,则会导致在直接比较时(此时被当作是有符号整数)无符号越大的值反而越小。

解决此类方法有两种方式:

第一种,使用 math.ult 进行比较无符号整数

local n1 = 0x7fffffffffffffff
local n2 = 0x8000000000000000
print(n1, n2, n1 < n2)              --> 9223372036854775807	-9223372036854775808	false
print(n1, n2, math.ult(n1, n2))     --> 9223372036854775807	-9223372036854775808	true

第二种,在进行有符号比较前先用掩码去两个操作数的符号位

local n3 = -10
local n4 = 10
local mask = 0x8000000000000000
print("有符号:", n3, "<", n4, n3 < n4)                     --> 有符号:	-10<10	true
print("无符号:", n4, "<", n3, math.ult(n4, n3))            --> 无符号:	10<-10	true
print("无符号:", n4, "<", n3, (n4 ~ mask) < (n3 ~ mask))   --> 无符号:	10<-10	true

2-5、细节五:整型数和浮点数互转

整型转浮点数

local u = 0xC000000000000000
print(math.type(u), string.format("%X", u))         --> integer	C000000000000000
-- + 0.0 是为将 u 转为 float , % 取余的规则符合通用规则,只要其中有一个为浮点数,结果则为浮点数
-- %(2 ^ 64) 是为将结果约束在这其中,否则显示时会被认为是有符号
local f = (u + 0.0) % 2 ^ 64
print(math.type(f), string.format("%.0f", f))       --> float	13835058055282163712
local f1 = (u + 0.0)
print(math.type(f1), string.format("%.0f", f1))     --> float	-4611686018427387904

浮点数转整型

function utointerger(value)
    if math.type(value) == "integer" then
        return value
    end
    -- f + 2 ^ 63 是为了让数转为一个大于 2 ^ 64 的数
    -- % (2 ^ 64) 是为了让数值限制在 [0, 2 ^ 64) 范围
    -- - 2 ^ 63 是为了把结果改为一个"负值"(最高位为 1 )
    -- 对于小于 2 ^ 63 的数:
    -- 其实没有什么特殊的,加完一个数值(2 ^ 63)之后有减掉了,所以没有什么特殊
    local result = math.tointeger(((value + 2 ^ 63) % (2 ^ 64)) - 2 ^ 63)
    return result + (math.tointeger(value - result) or 0)
end

local f = 0xF000000000000000.0
local u = utointerger(f)
print(math.type(u), string.format("%X", u))     --> integer	F000000000000000

值得注意:

因为这里是一个浮点数的计算,在我们之前的分享浮点数的文章中,有讲到 在 [-2^53, 2^53] 范围内,只需要将 整型数值 + 0.0 则可以进行转换为 浮点数,如果超出范围,会导致精度丢失,取近似值。

所以上述代码的 f 值如果超出这一范围,低位数可能会有问题

local f1 = 0x8000000000000001.0
local u1 = utointerger(f1)
print(math.type(u1), string.format("%X", u1))       --> integer	8000000000000000

三、二进制数据

Lua 从 5.3 开始提供了对二进制数和基本类型值之间进行转换的函数。

string.pack 会把值 “打包” 为二进制字符串

string.unpack 则从字符串中提取二进制

3-1、string.pack(fmt, v1, v2, …)

按照 fmt 格式将 v1、v2 进行打包为二进制字符串

参数:

  • fmt:打包格式
  • v1、v2:需要打包的数据

返回值:

字符串类型,即打包后的二进制数据

local format = "iii"
local s = string.pack(format, 3, -27, 450)
print(s, #s)        --> �����	12

3-2、string.unpack(fmt, s, pos)

按照 fmt 格式对字符串 s 偏移了 pos 个位置后,进行解析

参数:

  • fmt:解析格式
  • s:需要解析的字符串
  • pos:可选,从字符串 s 的第 pos 个位置开始解析,默认为 1

返回值:

会有两个返回值,第一个为解析后的内容,第二个为解析的字符串 s 中最后一个读取的元素在字符串中的位置。

local format = "iii"
local s = string.pack(format, 3, -27, 450)  --> �����	12
-- 最后的 13 即,最后一个读取的元素位置
print(string.unpack(format, s))             --> 3	-27	450	13

3-3、整型数格式可选参数

每种选项对应一种类型大小

格式描述
bchar
hshort
iint(可以跟一个数字,表示多少字节的整型数)
llong
jLua 语言中的整型数大小

3-3-1、固定字节

在使用 i 的时候,大小会与机器有关,如果想要达到固定大小,可以考虑在后面加上数字(1~16),类似 i8,则会产生 8 个字节的整型数。

local n1 = 1 << 54
print(string.format("%X", n1))          --> 40000000000000
local x1 = string.pack("i8", n1)
print(#x1, string.format("%X", string.unpack("i8", x1)))    --> 8	40000000000000

3-3-2、打包和解包都会检测溢出

打包的时候,如果发现字节不够装数值,则会抛出异常 bad argument #2 to 'pack' (integer overflow)

local x2 = string.pack("i8", 1 << 63)
print(string.format("%X", string.unpack("i8", x2)))

-- 打包会进行检查是否溢出
-- bad argument #2 to 'pack' (integer overflow)
print(string.pack("i7", 1 << 63))

解包也是一样的,会抛出异常 12-byte integer does not fit into Lua Integer ,因为对于 Lua 的整型数是 8 字节。

local x = string.pack("i12", 2 ^ 61)
print(string.unpack("i12", x))
x = "aaaa" .. "aaaa" .. "aaaa"
-- 解包也会检查是否能装得下
-- 12-byte integer does not fit into Lua Integer
--string.unpack("i12", x)

3-3-3、格式化无符号

每一个格式化选项都有一个大写的版本,对应无符号整型数:

local s = "\xFF"
print(string.unpack("b", s))        --> -1	2
print(string.unpack("B", s))        --> 255	2

3-4、字符串格式可选参数

可以使用三种形式打包字符串

格式描述
z\0 结尾的字符串
cn定长字符串,n 是被打包字符串的字节数
sn显式长度字符串,会在存储字符串前加上该字符串的长度,n 是用于保存字符串长度的无符号整型数的大小

举些例子

s1 表示将字符串长度保存在一个字节中

print("----- sn -----")
local s1 = string.pack("s1", "hello")
print("s1 长度", #s1)
for i = 1, #s1 do
    print(string.unpack("B", s1, i))
end

--> s1 长度	6
--> 5	2   (length)
--> 104	3   ('h')
--> 101	4   ('e')
--> 108	5   ('l')
--> 108	6   ('l')
--> 111	7   ('o')

s2 则表示用两个字节存储

s1 = string.pack("s2", "hello")
print("s2 长度", #s1)
for i = 1, #s1 do
    print(string.unpack("B", s1, i))
end

--> s2 长度	7
--> 5	2   (length)
--> 0	3   (length)
--> 104	4   ('h')
--> 101	5   ('e')
--> 108	6   ('l')
--> 108	7   ('l')
--> 111	8   ('o')

值得注意,如果保存长度的字节容纳不下字符串的长度,则会有抛出异常

当然也可以直接使用 s 进行打包字符串,会使用 size_t 类型进行保存,在 64 位的机子上,一般使用 8 个字节保存,大多数情况这会有些浪费。

s1 = string.pack("s", "hello")
print("s 长度", #s1)
print(string.unpack("s", s1, i))
for i = 1, #s1 do
    print(string.unpack("B", s1, i))
end

--> s 长度	13
--> hello	14
--> 5	2   (length)
--> 0	3   (length)
--> 0	4   (length)
--> 0	5   (length)
--> 0	6   (length)
--> 0	7   (length)
--> 0	8   (length)
--> 0	9   (length)
--> 104	10  ('h')
--> 101	11  ('e')
--> 108	12  ('l')
--> 108	13  ('l')
--> 111	14  ('o')

cn 打包固定长度自负串

-- 因为这里每个中文占 3 个字节,所以是 c9 ,后面打印也就有九行
local name = "江澎涌"
local fmt = string.format("c%d", #name)
local s3 = string.pack(fmt, name)
for i = 1, #s3 do
    print(string.unpack("B", s3, i))
end
print(string.unpack(fmt, s3))

--> 230	2
--> 177	3
--> 159	4
--> 230	5
--> 190	6
--> 142	7
--> 230	8
--> 182	9
--> 140	10
--> 江澎涌	10

3-5、浮点数格式可选参数

格式描述
f单精度浮点数
d双精度浮点数
nLua 语言浮点数
local p = string.pack("fdn", 3.14, 1.70, 10.89)
print(string.unpack("fdn", p))                  --> 3.1400001049042	1.7	10.89	21

3-6、大小端模式

默认情况下,格式使用的是机器原生的大小端模式。可以在格式中使用,一旦使用,后续的都会作用

格式描述
>大端模式、网络字节序
<小端模式
=改回机器默认模式

大端模式

local s1 = string.pack(">i2 i2", 500, 24)
for i = 1, #s1 do
    print(string.unpack("B", s1, i))
end

--> 1	2
--> 244	3
--> 0	4
--> 24	5

小端模式

local s2 = string.pack("<i2 i2", 500, 24)
for i = 1, #s2 do
    print(string.unpack("B", s2, i))
end

--> 244	2
--> 1	3
--> 24	4
--> 0	5

一图胜千言

改回默认

local s3 = string.pack(">i2 =i2", 500, 24)
for i = 1, #s3 do
    print(string.unpack("B", s3, i))
end

--> 1	2
--> 244	3
--> 24	4
--> 0	5

3-7、对齐数据

使用 !n 进行强制数据对齐到 n 为倍数的索引上。如果只是使用 ! 则会使用机器默认对其方式

如果数据比 n 小,则对其到其自身大小,否则对其到 n 上。

例如 !4 ,则 1 字节整型数会被写入以 1 位倍数的所以位置上,2 字节的整型数会被写入到以 2 为倍数的索引位置上,而 4 字节或更大的整型数会被写入到以 4 为倍数的索引位置上。

local s = string.pack("!4 i1 i2 i4", 10, 10, 10)
print("#s", #s)
for i = 1, #s do
    print(string.unpack("i1", s, i))
end

--> #s	8
--> 10	2
--> 0	3
--> 10	4
--> 0	5
--> 10	6
--> 0	7
--> 0	8
--> 0	9

string.pack 通过补 0 的形式实现对齐。string.unpack 则会在读取字符串时简单的跳过这些补位。

对齐只对 2 的整数次幂有效,如果不是则会报错 format asks for alignment not power of 2

在所有的格式化字符串默认的都会带有前缀 =!1,即表示使用默认的大小端模式且不对齐。

3-8、手工添加补位

可以通过 x 进行 1 字节的补位,string.pack 会在结果字符串中增加一个 0 字节,string.unpack 则会从目标字符串中跳过这一字节

local s = string.pack("i1i1xi1", 10, 10, 10)
print("#s", #s)
for i = 1, #s do
    print(string.unpack("i1", s, i))
end

--> #s	4
--> 10	2
--> 10	3
--> 0	4
--> 10	5

四、拓展一下

可以使用这一节的内容实现一些类似二进制文件查看器的功能,如下图所示

具体代码 https://github.com/zincPower/lua_study_2022/blob/master/7%20%E4%BD%8D%E5%92%8C%E5%AD%97%E8%8A%82/dump.lua

还可以对图片进行操作,具体可以看 https://github.com/zincPower/lua_study_2022/blob/master/7%20%E4%BD%8D%E5%92%8C%E5%AD%97%E8%8A%82/writeBinary.lua

五、写在最后

Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)

如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀

公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安全学习DAY17_信息打点-语言框架组件识别

信息打点-WEB打点-语言框架&开发组件 文章目录 信息打点-WEB打点-语言框架&开发组件本节涉及链接&工具本节知识&思维导图基础概念介绍框架&#xff1a;组件&#xff1a;Web架构 对应Web测试手法后端&#xff1a;前端组件&#xff1a;java居多&#xff0c;框架&…

RP2040开发板自制树莓派逻辑分析仪

目录 前言 1 准备工作和前提条件 1.1 Raspberry Pi Pico RP2040板子一个 1.2 Firmware-LogicAnalyzer-5.0.0.0-PICO.uf2固件 1.3 LogicAnalyzer-5.0.0.0-win-x64软件 2 操作指南 2.1 按住Raspberry Pi Pico开发板的BOOTSEL按键&#xff0c;再接上USB接口到电脑 2.2 刷入…

产品帮助中心怎么做?这两点不能忽略,让用户自助解决问题!

对于大部分线上产品&#xff0c;因为其功能和系统的复杂性&#xff0c;使得新手客户入门学习非常复杂&#xff0c;为了快速响应并且解决问题&#xff0c;一套系统完整的产品帮助中心必不可少&#xff01; 产品帮助中心 因此&#xff0c;对于很多产品开发者来说&#xff0c;借助…

pg简单使用

1.创建服务器 2.创建数据库 3.修改默认连接数据库 工具都是链接到这里 4.数据库代码工具

ByteBuffer 使用

ByteBuffer 使用 1 java.nio包中的类定义的缓冲区类型2 缓冲区常用属性2.1缓冲区的容量(capacity)2.2 缓冲区的位置(position)2.3 缓冲区的限制(limit)2.4 缓冲区的标记(mark)2.5 剩余容量 remaining/hasRemaining 3 缓冲区常用方法3.1 创建缓冲区3.1.1 allocate方法3.1.2 wrap…

交叉编译之wiringPi库,【全志H616,orangepi-zero2】

文章目录 书接上回wiringPi全志库下载建立软链接软连接软连接创建 硬链接硬链接创建 测试树莓派运行servo文件 结束 书接上回 上回已经完整的安装了全志的gcc交叉编译工具 https://blog.csdn.net/qq_52749711/article/details/132306764 wiringPi全志库下载 下载链接 先搞到…

Jmeter+ant+jenkins实现持续集成

jmeterantjenkins持续集成 一、下载并配置jmeter 首先下载jmeter工具&#xff0c;并配置好环境变量&#xff1b;参考&#xff1a;https://www.cnblogs.com/YouJeffrey/p/16029894.html jmeter默认保存的是.jtl格式的文件&#xff0c;要设置一下bin/jmeter.properties,文件内容…

中国电信物联网收入33亿元,用户达到4.73亿户!

近日&#xff0c;中国电信发布2023中期业绩&#xff0c;物联网迎来强劲增长&#xff0c;物联网收入33亿元&#xff0c;同比增长75.7%&#xff0c;物联网用户4.73亿户&#xff0c;同比增长31.5%。天翼物联自主研发的AIoT物联网平台&#xff0c;升级为云原生3AZ架构&#xff0c;提…

在线课堂录播直播管理系统SpringBoot+Vue

在线课堂录播直播管理系统SpringBootVue 文章目录 在线课堂录播直播管理系统SpringBootVue共三个端&#xff1a;后端、后台管理系统、前端&#xff0c;如要学习看评论区&#xff08;全部源码、文档、数据库&#xff09;。内置功能一、前端二、后台管理三、后端--代码全有。四、…

k8s 认证和权限控制

k8s 的认证机制是啥&#xff1f; 说到 k8s 的认证机制&#xff0c;其实之前咋那么也有提到过 ServiceAccouont &#xff0c;以及相应的 token &#xff0c;证书 crt&#xff0c;和基于 HTTP 的认证等等 k8s 会使用如上几种方式来获取客户端身份信息&#xff0c;不限于上面几种…

【数据结构OJ题】链表分割

原题链接&#xff1a;https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId8&&tqId11004&rp2&ru/activity/oj&qru/ta/cracking-the-coding-interview/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2…

Java面向对象——封装以及this关键字

封 装 封装是面向对象编程&#xff08;OOP&#xff09;的三大特性之一&#xff0c;它将数据和操作数据的方法组合在一个单元内部&#xff0c;并对外部隐藏其具体实现细节。在Java中&#xff0c;封装是通过类的访问控制修饰符&#xff08;如 private、protected、public&#x…

Android Drawable转BitmapDrawable再提取Bitmap,Kotlin

Android Drawable转BitmapDrawable再提取Bitmap&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"…

C++ 结构体的对齐

C 结构体的对齐 flyfish 文章目录 C 结构体的对齐一 非对齐方式二 对齐方式示例1示例2 三 对齐到指定字节数 boundary 一 非对齐方式 也就是按照1字节对齐 #pragma pack(1) typedef unsigned char BYTE; typedef struct message {BYTE a[4];BYTE b[2];BYTE *c;BYTE d[4];} M…

阿里云ECS服务器企业级和共享型介绍_企业级常见问题解答FAQ

阿里云企业级服务器是什么&#xff1f;企业级和共享型有什么区别&#xff1f;企业级服务器具有独享且稳定的计算、存储、网络资源&#xff0c;如ECS计算型c6、通用型g8等都是企业级实例&#xff0c;阿里云百科分享什么是企业级云服务器、企业级实例的优势、企业级和共享型云服务…

如何收缩wsl2虚拟磁盘

简介 WSL2使用虚拟化层为它带来更高的性能和兼容性。但是&#xff0c;WSL2 的少数缺点之一是它使用虚拟磁盘 &#xff08;VHDX&#xff09; 来存储文件系统。这意味着您的虚拟磁盘占用了 100GB&#xff0c;但 WSL2 只需要 15GB... 所以要寻找一种缩小 WSL2 虚拟磁盘的方法&…

​Redis概述

目录 Redis - 概述 使用场景 如何安装 Window 下安装 Linux 下安装 docker直接进行安装 下载Redis镜像 Redis启动检查常用命令 Redis - 概述 redis是一款高性能的开源NOSQL系列的非关系型数据库,Redis是用C语言开发的一个开源的高键值对(key value)数据库,官方提供测试…

Leetcode每日一题:1444. 切披萨的方案数(2023.8.17 C++)

目录 1444. 切披萨的方案数 题目描述&#xff1a; 实现代码与解析&#xff1a; 二维后缀和 动态规划 原理思路&#xff1a; 1444. 切披萨的方案数 题目描述&#xff1a; 给你一个 rows x cols 大小的矩形披萨和一个整数 k &#xff0c;矩形包含两种字符&#xff1a; A …

根据Dockerfile创建容器案例讲解

-f为dokerfile的路径&#xff0c; -t为新镜像的名称及版本。 后面这个点是寻址路径。

【第三阶段】kotlin语言的字符串遍历操作

fun main() {val str1:String"AFWSDKFJWIUHGWINUWVRV"str1.forEach(){ it->println("所有字符&#xff1a;$it")} }执行结果