文章目录

  • Lua 编程学习笔记
    • 一、环境安装
    • 二、Lua 基本语法
      • 1. 注释
      • 2. 标识符
      • 3. 变量
      • 4. 数据类型
      • 5. Lua 运算符
    • 三、循环与流程控制
      • 1. 循环
      • 2. 流程控制
    • 四、函数
      • 1. 基本定义
      • 2. 可变参数
      • 3. 函数作为参数传递
    • 五、表与数组
      • 1. 基本定义
      • 2. 表操作的常用方法
        • 2.1 插入数据
        • 2.2 删除数据
        • 2.3 拼接表数据
        • 2.4 排序
    • 六、模块与包
      • 1. 模块定义
      • 2. 包的引入
    • 七、元表
      • 1. 基本定义
      • 2. 元方法
        • 2.1 __index 元方法
          • 总结
        • 2.2 __newIndex 元方法
        • 2.3 __tostring 元方法
    • 八、协同程序
      • 1. 常用方法:
      • 2. 经典生产消费问题
    • 九、文件IO
      • 1. 简单模式
      • 2. 完全模式
    • 十、面向对象
    • 十一、饥荒源码Lua学习

Lua 编程学习笔记

Lua编程语言给人的感觉是小巧,简洁,解释性语言,弱类型,主要用于游戏开发,嵌入式脚本开发。

此次学习源于写饥荒脚本,用饥荒学习Lua绝对是不错的一个实战。

一、环境安装

首先在官网下载

Lua下载是一个压缩文件,解压即可用,但是需要先编译一下。

默认是没有可执行程序的,需要使用命令制作一下。

在当前src目录下打开终端窗口,执行命令

make

make之后生成lualuac两个可执行程序

这样我们就可以用Lua这个可执行程序执行我们编写的.lua文件了。

我使用的是IDE是Idea,Idea需要编写Lua需要下载一个插件:EmmyLua

使用这个插件可以高亮显示还有方法提示,可以Tab键自动补全。

安装后运行Lua文件的需要配置文件的解释程序。

这样整体的开发环境就搭配好了。


二、Lua 基本语法

1. 注释

单行注释

-- Lua 的单行注释使用 `--`
print("Hello Lua")

多行注释

--[[多行注释1多行注释2多行注释3
]]
print("Hello Lua")

2. 标识符

和其他编程语言一样,Lua的标识符由字母、数字以及下划线组成,且不能以数字开头,不能是关键字
比如:__index

3. 变量

Lua作为弱类型语言,变量的定义不需要声明数据类型。

-- 整数变量 a
a = 1-- 字符串变量 a
a = "Test"-- 布尔类型 a
a = false

变量的作用域默认是全局,只有声明为local的变量才是局部变量

弱类型语言的变量使用很随意,如果变量的数据类型使用错误,只有在运行时才能发现,体现的是规范大于约定的思想。

4. 数据类型

虽然变量的定义不需要声明数据类型,但是Lua大体上还是分为8种数据类型

  • nil
  • number
  • string
  • boolean
  • function
  • table
  • userdata
  • thread

nil代表空值,被赋值为nil的变量将清空,userdata和thread目前还没接触,其他类型只有nil和table的概念比较特殊。

注:Lua中的布尔值只有nil和false为条件表达式的否判断。

-- number类型也是真值
a = 1
if a thenprint("a是ture")
end -- 函数类型也是真值
function fn() print("fn函数")
end
if fn thenprint("fn函数只要不为nil也是真值")
end

5. Lua 运算符

1)算术运算符

  • + 加法
  • - 减法
  • * 乘法
  • / 除法(真实运算,不会取整数,Java里边10/3=3,这里10/3=3.3333333333333)
  • % 求余
  • ^ 幂运算( 2^3=8.0)
  • - 负号,对数字前面直接加取负数
  • // 整数运算,这个才是同Java的除法运算,10/3=3

2)逻辑运算符

  • and 逻辑与运算
  • or 逻辑或运算
  • not 逻辑非运算

3)关系运算符

  • >
  • <
  • ==
  • >=
  • <=
  • ~=

注意Lua的不等于写法~= 这个还是挺新鲜的写法。

4)其他运算符

Lua 没有类似++, --的操作,循环时候一定要注意!

  • .. 拼接字符串,同Java的 + 拼接字符串
  • # 返回字符串或者表的长度
print(#"Hello")     -- 输出 5tab = {1,2,3}
print(tab)          -- 输出3

三、循环与流程控制

Lua循环和其他语言类似,只是需要注意基本的格式。

1. 循环

三种循环方式

  • while
  • for
  • repeat … until
-- 方式一 while 循环
a = 0
while a < 10 doprint("while循环"..a)a = a + 1
end-- 方式二 for 循环
for i = 1, 10 doprint("for循环"..i)
end-- 方式三 repeat 循环
c = 0
repeatprint("repeat循环"..c)c = c + 1
until c > 10

repeat … until 循环好比是Java中的 do…while循环,至少执行一次。

2. 流程控制

-- if 结构
if a>b thenreturn a
end-- if elseif else 结构
if a > 90 thenprint("优秀")
elseif a > 80 thenprint("良好")
elseif a > 60 thenprint("及格")
elseprint("不及格")
end

循环和流程控制都没有特殊的,需要注意的是基本格式,Lua里边无论函数还是循环控制,都是以end结尾

四、函数

Lua函数比较特殊,第一次遇到可以返回多个值。

1. 基本定义

-- 方式一
function f1()-- do something
end-- 方式二
local f2 = function(arg1,arg2,arg3) -- do somethingreturn arg1,arg2,arg3
end

Lua的函数修饰符只有local定义是否为局部函数,参数可选。主要是可以类似函数f2,可以返回多个数据。

接收函数返回值的时候也可以多个变量一一对应接收。

function f3()return 1,2,3
enda,b,c = f3()
print(a,b,c)    -- 输出 1,2,3

2. 可变参数

函数接收可变参数有个内置变量arg这个需要主要,他是一个表table

-- `...` 代表可变参数
function f4(...)local arg = {...}-- 遍历方式一for k, v in pairs(arg) doprint(k,v)end-- 遍历方式二for k, v in ipairs{...} doprint(k,v)endprint(#arg)                         -- 定义 local = {...} 可通过 #arg 获取参数个数print(select("#",...))       -- select("#",...) 获取可变参数个数
endf4(1,2,3,4)                             -- 最后打印 4-- 函数作为参数传递function f5(func)local ret = funcend

注:可变参数的获取方式和数据获取方式是重点

另外,ipairs和pairs的主要区别是ipairs遇到nil则会停下来,而pairs遍历不会。

for k,v in pairs(table) do … end 这是一种基本固定的遍历表的写法,类似Java中的增强for循环。

3. 函数作为参数传递

函数作为参数传递给下个函数时,函数内可以调用这个函数做一些数据处理

function max(a,b)if a > b thenreturn aelsereturn bend
endfunction printMax(a,b,maxFunc)print(maxFunc(a,b))
endprintMax(2,3,max)

五、表与数组

表是Lua中最常用的数据结构了,基本上数据的使用都是通过表,但我理解更像是一个Map容器,存储一些key,value的键值对。

1. 基本定义

-- 数组没有单独的表示方式,数组就是用表表示的,只不过没有key,默认key就是1,2,3...连续索引
-- 一对花括号就代表这是一个表,前面的数据类型有一个就是table表数据类型
tab = {}-- 也可以初始化(数组)
fruits = {"apple","peach","banana"}-- 这个更应该被认为是表,以指定的key-value形式存在
table_define = {key1 = "val",key2 = "val2",key3 = "val3"
}-- 或者给表增加数据
tab["key"] = "value"-- 赋值 nil 就清空了一个表
tab = nil-- 表的引用赋值给另一个
newFruits = fruits
fruits = nil            -- newFruits 指向的表实际还在,这里只是清空了fruits的引用而已

2. 表操作的常用方法

注:Lua中的索引都是从1开始的,而不是0!

2.1 插入数据

tab = {}
-- 默认插入表的末尾
table.insert(tab,"value1")
print(tab[1])-- 插入指定索引位置
table.insert(tab,1,"value2")print(tab[1])

2.2 删除数据

fruits = {"apple", "peach", "banana", "orange"}fruits[1] = nil
print(fruits[1])        -- niltable.remove(fruits,2)
print(fruits[2])        -- banana-- 默认移除表最后的数据
table.remove(fruits)
for k,v in pairs(fruits) doprint(v)            -- banana
end

2.3 拼接表数据

tab = {"Lua", "C#", "Java"}-- 拼接数据元素
print(table.concat(tab))                   -- LuaC#Java-- 指定拼接的分隔符
print(table.concat(tab," "))               -- Lua C# Java-- 指定分隔符和指定索引范围内数据拼接
print(table.concat(tab," ",2,3))           -- C# Java

2.4 排序

tab = {"Lua", "C#", "Java"}-- 调用table的排序方法
table.sort(tab)

六、模块与包

这里才是最接近编程开发的概念了,将代码进行模块化管理,但是Lua并没有真正的包Module的概念,包也是通过表来实现的。

1. 模块定义

Module = {}Module.name = "模块包"Module.func = function() print("文件module.lua中的函数func")
end-- 可以通过local封装,只能通过方法调用
local address = "SZ"
Module.getAddress = function()return address
endlocal func_local = function()print("local函数")
endModule.getLocalFunc = function()func_local()
end

2. 包的引入

包的引入使用关键字require

-- 两种写法,之类的module,是文件名,module.lua这个文件就被引入进来了
require "module"require("module")-- 引入包之后就可以访问包的内容了
print(Module.name)
Module.func()print(Module.getAddress())
print(Module.getLocalFunc())

七、元表

元表理解更像是定义那样,更微小的单元,他允许我们去定义一个表之外的行为,除了赠删改之外的动作。比如两个表进行相加。

1. 基本定义

myTable = {}    -- 普通表
myMetaTable = {}    -- 元表
-- 会返回普通表
myTable = setmetatable(myTable,myMetaTable) -- 将myMetaTable设置为myTable的元表getmetatable(myTable)   -- 返回 myMetaTable 元表 

2. 元方法

2.1 __index 元方法

当查找普通表中的key对应值为没有时,则去调用此方法寻找对应的表中的数据。

理解更像是对普通表的一种扩展。

other = {key = 3}
t = setmetatable({},{__index = other})  -- 普通表是空的,元表存在元素 key = 3print(t.key)    -- 3

如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。
__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。

mytable = setmetatable({ key1 = "value1" } , { __index = function(mytable,key)if  key == "key2" thenreturn "metatablevalue"elsereturn nilendend
})
print(mytable.key1,mytable.key2)
总结

来源菜鸟教程

Lua 查找一个表元素时的规则,其实就是如下 3 个步骤:

  1. 在表中查找,如果找到,返回该元素,找不到则继续
  2. 判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
  3. 判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;
    1. 如果 __index 方法是一个表,则重复 1、2、3;
    2. 如果 __index 方法是一个函数,则返回该函数的返回值。

2.2 __newIndex 元方法

__newIndex针对不存在的key进行赋值时候调用

mytable = setmetatable({key1 = "value1"}, {__newindex = function(mytable, key, value)rawset(mytable, key, "\""..value.."\"")end
})mytable.key1 = "new value"
mytable.key2 = 4print(mytable.key1,mytable.key2)

2.3 __tostring 元方法

__tostring使得print(table)时候可以输出字符串而不是表的引用

mytable = setmetatable({ 10, 20, 30 }, {__tostring = function(mytable)sum = 0for k, v in pairs(mytable) dosum = sum + vendreturn "表所有元素的和为 " .. sumend
})
print(mytable)

八、协同程序

协同程序实际上就是协同函数,让函数可以再执行到一半的时候挂起,然后再继续执行下面的代码,知道执行启动该协同函数才会继续执行协同函数肚饿代码。

1. 常用方法:

  • coroutine.create(func) 创建一个协同函数,参数为函数
  • coroutine.resume() 启动创建的协同函数,搭配coroutine.create()
  • coroutine.yield() 暂停协同函数,参数可以作为函数的返回值,同return效果
  • coroutine.status() 查看协同函数的状态,存在三种:suspended,dead,running分别为暂停,死亡,运行
  • coroutine.wrap() 同create+resume,创建并启动,停止后好像没法继续启动
  • coroutine.running() 返回正在跑的coroutine,一个正在跑的coroutine就是一个线程

2. 经典生产消费问题

local co-- 生产者每生产一个就提供给消费者
function productor()local i = 0while true doi = i + 1print("生产者生产\t"..i)sleep(1)coroutine.yield(i)endprint("无产品生产,生产者结束")
endfunction consumer()while coroutine.status(co) ~= "dead" doprint("消费者唤醒生产")local status, value = coroutine.resume(co)print("消费者消费\t"..value)sleep(1)endprint("消费者得知生产结束,消费结束")
endfunction sleep(n)local t = os.clock()while os.clock() -t <=n do end
end-- 创建生产者协同函数
co = coroutine.create(productor)
-- 开始消费
consumer()

注:Lua语言没有原生的线程睡眠函数,这里定义的也不是很懂,大概理解是os.clock返回程序运行时长,用时间差判断得到睡眠时间。

九、文件IO

文件IO分为简单模式和完全模式,文件打开针对权限分为:

  • r 只读,文件必须存在
  • w 只写,以覆盖的方式写入
  • a 只写,以附加的方式写入
  • r+ 可读写,文件必须存在
  • w+ 可读写,文件存在则覆盖,文件不存在则创建
  • a+ 可读写,以附加的方式写入
  • b 二进制文件,如果打开的是二进制文件需要加上 b
  • 表示可读可写

1. 简单模式

-- 以只读的方式打开一个文件
file = io.open("tmp.txt","r")-- 设置io的输入文件是file
io.input(file)-- 读取一行
line = io.read()-- 关闭文件也要指定文件
io.close(file)

2. 完全模式

-- 以只读的方式打开tmp.txt文件
file = io.open("tmp.txt", "r")-- 直接读取一行,不用io.input(file)指定输入文件了
line = file:read()-- 关闭文件
file:close()

上面的read方法都是默认读取一行数据,可以指定read()函数的参数,代表不同的读取方法

  • *n 读取一个数字并返回,必须是数字
  • *a 读取整个文件内容
  • *| 读取一行(默认方式)测试时候好像一直报错,未知原因
  • number 举例:file.read(4) 指定读取4个字符

十、面向对象

Lua的面向对象的使用应该才是最终极的形态了。

面向对象逃不开三个特征,封装、继承、多态。

  • 封装 有效封装属性,合理对外暴露。
  • 继承 对父类属性的扩展,比如存在人这个模型,可以将学生对象继承自父类对象人,使其具备人有的一些属性方法。
  • 多态 一种类型的多种形态,按照Java的说法就是父类的引用指向子类的对象,比如数据都是动物,但是可以不同的形态如,猫,狗都属于动物

对象

-- Lua 里边都是表数据,没有对象的概念,所以所谓类,对象都是模拟出来的一种形态-- 定义一个Person类
Person = {name = nil,age = nil
}-- 定义方法
Person.eat = function(self)print(self.name.."在吃东西")
end-- 调用
Person.name = "周杰伦"
Person.age = 42
Person.eat(Person)-- 如果还有一个Person对象,则需要再次重复定义上面的Person,所以可以模拟一个类的构造方法出来
function Person:new(o)local t = o or {}setmetatable(t, {__index = self})return t
end-- eat 方法改进,后面编程都是以这种形式出现的居多
function Person:eat()print(self.name.."在吃东西")
endp1 = Person:new()
p1.name = "黄圣依"
print(p1:eat())

十一、饥荒源码Lua学习

饥荒里边的源码都是Lua文件,采用ECS(Entity, Components, System)框架,即实体、组建、系统。

这种框架和面向对象不同,他更多的是面向数据;
实体理解就是对象,一个一个的实物,比如游戏里边的花、猪人,兔子等,而组件则是行为,比如花存在可采集的属性,所以Pickable.lua文件存在组件中代码。

而系统则是控制整个游戏的机制玩法。系统不关心组件存在什么行为,组件不关系实体具体是什么。

饥荒中类的定义
class.lua文件–基本上看完感觉上面的Lua都白学了,吐了。

-- class.lua
-- Compatible with Lua 5.1 (not 5.0).local TrackClassInstances = falseClassRegistry = {}if TrackClassInstances == true thenglobal("ClassTrackingTable")global("ClassTrackingInterval")ClassTrackingInterval = 100
endlocal function __index(t, k)local p = rawget(t, "_")[k]if p ~= nil thenreturn p[1]endreturn getmetatable(t)[k]
endlocal function __newindex(t, k, v)local p = rawget(t, "_")[k]if p == nil thenrawset(t, k, v)elselocal old = p[1]p[1] = vp[2](t, v, old)end
endlocal function __dummy()
endlocal function onreadonly(t, v, old)assert(v == old, "Cannot change read only property")
endfunction makereadonly(t, k)local _ = rawget(t, "_")assert(_ ~= nil, "Class does not support read only properties")local p = _[k]if p == nil then_[k] = { t[k], onreadonly }rawset(t, k, nil)elsep[2] = onreadonlyend
endfunction addsetter(t, k, fn)local _ = rawget(t, "_")assert(_ ~= nil, "Class does not support property setters")local p = _[k]if p == nil then_[k] = { t[k], fn }rawset(t, k, nil)elsep[2] = fnend
endfunction removesetter(t, k)local _ = rawget(t, "_")if _ ~= nil and _[k] ~= nil thenrawset(t, k, _[k][1])_[k] = nilend
endfunction Class(base, _ctor, props)local c = {}    -- a new class instancelocal c_inherited = {}if not _ctor and type(base) == 'function' then_ctor = basebase = nilelseif type(base) == 'table' then-- our new class is a shallow copy of the base class!-- while at it also store our inherited members so we can get rid of them-- while monkey patching for the hot reload-- if our class redefined a function peronally the function pointed to by our member is not the in in our inherited-- tablefor i,v in pairs(base) doc[i] = vc_inherited[i] = vendc._base = baseend-- the class will be the metatable for all its objects,-- and they will look up their methods in it.if props ~= nil thenc.__index = __indexc.__newindex = __newindexelsec.__index = cend-- expose a constructor which can be called by <classname>(<args>)local mt = {}if TrackClassInstances == true and CWD~=nil thenif ClassTrackingTable == nil thenClassTrackingTable = {}endClassTrackingTable[mt] = {}local dataroot = "@"..CWD.."\\"local tablemt = {}setmetatable(ClassTrackingTable[mt], tablemt)tablemt.__mode = "k"         -- now the instancetracker has weak keyslocal source = "**unknown**"if _ctor then-- what is the file this ctor was created in?local info = debug.getinfo(_ctor, "S")-- strip the drive letter-- convert / to \\source = info.sourcesource = string.gsub(source, "/", "\\")source = string.gsub(source, dataroot, "")local path = sourcelocal file = io.open(path, "r")if file ~= nil thenlocal count = 1for i in file:lines() doif count == info.linedefined thensource = i-- okay, this line is a class definition-- so it's [local] name = Class etc-- take everything before the =local equalsPos = string.find(source,"=")if equalsPos thensource = string.sub(source,1,equalsPos-1)end-- remove trailing and leading whitespacesource = source:gsub("^%s*(.-)%s*$", "%1")-- do we start with local? if so, strip itif string.find(source,"local ") ~= nil thensource = string.sub(source,7)end-- trim again, because there may be multiple spacessource = source:gsub("^%s*(.-)%s*$", "%1")breakendcount = count + 1endfile:close()endendmt.__call = function(class_tbl, ...)local obj = {}if props ~= nil thenobj._ = { _ = { nil, __dummy } }for k, v in pairs(props) doobj._[k] = { nil, v }endendsetmetatable(obj, c)ClassTrackingTable[mt][obj] = sourceif c._ctor thenc._ctor(obj, ...)endreturn objendelsemt.__call = function(class_tbl, ...)local obj = {}if props ~= nil thenobj._ = { _ = { nil, __dummy } }for k, v in pairs(props) doobj._[k] = { nil, v }endendsetmetatable(obj, c)if c._ctor thenc._ctor(obj, ...)endreturn objendendc._ctor = _ctorc.is_a = function(self, klass)local m = getmetatable(self)while m doif m == klass then return true endm = m._baseendreturn falseendsetmetatable(c, mt)ClassRegistry[c] = c_inherited--    local count = 0--    for i,v in pairs(ClassRegistry) do--        count = count + 1--    end--    if string.split then--        print("ClassRegistry size : "..tostring(count))--    endreturn c
endfunction ReloadedClass(mt)ClassRegistry[mt] = nil
endlocal lastClassTrackingDumpTick = 0function HandleClassInstanceTracking()if TrackClassInstances and CWD~=nil thenlastClassTrackingDumpTick = lastClassTrackingDumpTick + 1if lastClassTrackingDumpTick >= ClassTrackingInterval thencollectgarbage()print("------------------------------------------------------------------------------------------------------------")lastClassTrackingDumpTick = 0if ClassTrackingTable thenlocal sorted = {}local index = 1for i,v in pairs(ClassTrackingTable) dolocal count = 0local first = nilfor j,k in pairs(v) doif count == 1 thenfirst = kendcount = count + 1endif count>1 thensorted[#sorted+1] = {first, count-1}endindex = index + 1end-- get the top 10table.sort(sorted, function(a,b) return a[2] > b[2] end )for i=1,10 dolocal entry = sorted[i]if entry thenprint(tostring(i).." : "..tostring(sorted[i][1]).." - "..tostring(sorted[i][2]))endendprint("------------------------------------------------------------------------------------------------------------")endendend
end

Lua 编程学习笔记相关推荐

  1. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记--async和await(一) 接上文 多线程编程学习笔记--async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  2. 多线程编程学习笔记——任务并行库(二)

    接上文 多线程编程学习笔记--任务并行库(一) 三.   组合任务 本示例是学习如何设置相互依赖的任务.我们学习如何创建一个任务的子任务,这个子任务必须在父任务执行结束之后,再执行. 1,示例代码如下 ...

  3. 多线程编程学习笔记——任务并行库(三)

    接上文 多线程编程学习笔记--任务并行库(一) 接上文 多线程编程学习笔记--任务并行库(二) 六.   实现取消选项 本示例学习如何实现基于Task的异步操作进行取消流程,以及在任务真正运行前如何知 ...

  4. Linux与C++11多线程编程(学习笔记)

    多线程编程与资源同步 在Windows下,主线程退出后,子线程也会被关闭; 在Linux下,主线程退出后,系统不会关闭子线程,这样就产生了僵尸进程 3.2.1创建线程 Linux 线程的创建 #inc ...

  5. Cocoa编程学习笔记一

    Cocoa编程学习笔记一 一.Cocoa的起源 Mac OS X的窗口服务器与UNIX中的X窗口服务器具有相同的功能:从用户那里接受事件,并将时间转发给应用程序,将应用程序发过来的数据显示在屏幕上.N ...

  6. 多线程编程学习笔记——使用并发集合(三)

    接上文 多线程编程学习笔记--使用并发集合(一) 接上文 多线程编程学习笔记--使用并发集合(二) 四.   使用ConcurrentBag创建一个可扩展的爬虫 本示例在多个独立的即可生产任务又可消费 ...

  7. Java 8 函数式编程学习笔记

    Java 8 函数式编程学习笔记 @(JAVASE)[java8, 函数式编程, lambda] Java 8 函数式编程学习笔记 参考内容 Java 8中重要的函数接口 扩展函数接口 常用的流操作 ...

  8. java 网络编程学习笔记

    java 网络编程学习笔记 C/S模式:客户端和服务器 客户端创建流程 1 1.建立Socket端点 2 3 Socket s = new Socket(绑定地址, 绑定端口); 2.确认源数据方式和 ...

  9. lua本学习笔记功能

    Lua本学习笔记功能 1.  函数返回 指定任务的主要功能是完成,在这种情况下,函数被用作调用语句.函数可以计算并返回值,在这种情况下,作为分配值表达式语句使用. 语法: funcationfunc_ ...

最新文章

  1. .Net Compact Framework实现文件下载功能
  2. 如何搭建基于容器的工业互联网PaaS平台
  3. 操作系统课设--系统调用
  4. VTK:Filtering之ConnectivityFilter
  5. cocos2d-x游戏实例(1)-视角跟随主角
  6. JS判断访问设备(userAgent)加载不同页面 JS判断客户端操作系统类型(platform)
  7. spring之基本介绍以及老版本框架的下载地址
  8. 腾讯广告算法大赛已启动,逆向算法,等你来战
  9. html货币相关符号
  10. 英雄联盟游戏结束后显示与服务器失去连接,英雄联盟游戏被终止连接不上解决方法...
  11. Excel基础知识(10):多工作簿数据的引用与更新
  12. 如何批量隔行删除Excel行
  13. JTree创建、获取和删除节点的方法
  14. 各大著名汽车标志图 来历
  15. app运营,如何提高用户的参与度?
  16. 按自己的需要获取对象中的属性
  17. ueditor统计字数中文_百度UEditor修改右下角统计字数包含html样式
  18. java 蓝牙打印_Android - 将收据打印到蓝牙打印机
  19. 删除win10桌面上IE的方法
  20. 《算法零基础100讲》(第42讲) 位运算 (位与) 入门

热门文章

  1. python实现爬虫探探_全栈 - 9 实战 爬取豆瓣电影数据
  2. 超强古文...... yi
  3. OpenCV-Python之画椭圆
  4. win7连接sftp_WinSCP(SFTP客户端)官方版下载_WinSCP(SFTP客户端) v5.17.7.10640中文版 - Win7旗舰版...
  5. order by语句使用
  6. drag与drop事件
  7. Android App包瘦身优化
  8. SharePoint服务器端对象模型 之 使用CAML进行数据查询
  9. 暗黑2符文之语大全_暗黑破坏神2符文之语一览,附符文镶嵌顺序和底材
  10. 工具--国内最常用开源镜像站大汇总,解决你下载软件慢的问题