Lua 15分钟快速上手(下)

2023-11-12

本系列相关文章:
Flutter 热更新及动态UI生成
Lua 15分钟快速上手(上)
Lua 15分钟快速上手(下)
Lua与C语言的互相调用
LuaDardo中Dart与Lua的相互调用

进阶语法篇

迭代器

迭代器(iterator)是一种可以让我们遍历一个集合中所有元素的代码结构。在Lua语言中,通常使用函数表示迭代器:每一次调用函数时,函数会返回集合中的“下一个”元素。

泛型for迭代器

泛型for在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。语法格式如下:

for var-list in exp-list do
    body
end

var-list是由一个或多个变量名组成的列表,以逗号分隔;exp-list是一个或多个表达式组成的列表,同样以逗号分隔。通常,表达式列表只有一个元素,即一句对迭代器工厂的调用。Lua把变量列表的第一个(或唯一的)变量称为控制变量(control variable),其值在循环过程中永远不会是nil,因为当其值为nil时循环就结束了。

实例:

array = {'Ali','Sina','Meituan'}

for key,value in ipairs(array) do
   print(key, value)
end

执行过程

  1. 初始化,计算 in 后面表达式的值,表达式应该返回通用 for 需要的三个值:迭代函数、状态常量、控制变量

    与多值赋值一样,如果表达式返回的结果个数不足三个会自动用 nil 补足,多出部分会被忽略

  2. 将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)

  3. 将迭代函数返回的值赋给变量列表

  4. 如果返回的第一个值为 nil 循环结束,否则执行循环体

  5. 回到第二步再次调用迭代函数

一般来说,迭代器包含两种类型:

  1. 无状态的迭代器
  2. 多状态的迭代器

无状态的迭代器

无状态的迭代器是指不保留任何状态的迭代器。使用无状态迭代器避免创建新闭包的开销。一般情况下,每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用。 一个无状态的迭代器只利用这两个值可以获取下一个元素。

ipairs就是一种无状态迭代器 ,它遍历数组的每一个元素。

实现一个无状态的迭代器:

function iter (a, i)
    i = i + 1
    local v = a[i]
    if v then
       return i, v
    end
end

function mypairs (a)
    return iter, a, 0 -- 返回三个值
end

array = {'Ali','Sina','Meituan'}

for key,value in mypairs(array) do
   print(key, value)
end

多状态的迭代器

迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,这时有两种实现方式:

  1. 使用闭包
  2. 将所有的状态信息封装到 table 内,将 table 作为迭代器的状态常量 因为这种情况下可以将所有的信息存放在 table 内,所以迭代函数通常不需要第二个参数

使用闭包示例:

function walk_it(collection)
   local index = 0
   local count = #collection
   -- 闭包函数
   return function ()
      index = index + 1
      if index <= count
      then
         --  返回迭代器的当前元素
         return collection[index]
      end
   end
end

array = {'Ali','Sina','Meituan'}

for value in walk_it(array) do
   print(value)
end

“迭代器”这个名称多少有点误导性,这是因为迭代器并没有进行实际的迭代:真正的迭代是for循环完成的,迭代器只不过为每次的迭代提供连续的值。或许,称其为“生成器(generator)”更好,表示为迭代生成(generate)元素;不过,“迭代器”这个名字已在诸如Java等其他语言中被广泛使用了。

元表

元表(Metatable)是面向对象领域中的受限制类。像类一样,元表定义的是实例的行为。不过,由于元表只能给出预先定义的操作集合的行为,所以元表比类更受限;同时,元表也不支持继承。

Lua语言中的每种类型的值都有一套可预见的操作集合。例如,我们可以将数字相加,可以连接字符串,还可以在表中插入键值对等。但是,我们无法将两个表相加,无法对函数作比较,也无法调用一个字符串,这时就需要使用元表。例如,假设a和b都是表,那么可以通过元表定义Lua语言如何计算表达式a+b。当Lua语言试图将两个表相加时,它会先检查两者之一是否有元表(metatable)且该元表中是否有__add字段。如果Lua语言找到了该字段,就调用该字段对应的值,即所谓的元方法(metamethod,是一个函数),用于计算两个表的和的函数。

Lua语言中的每一个值都可以有元表。每一个表和用户数据类型都具有各自独立的元表,而其他类型的值则共享对应类型所属的同一个元表。但我们只能为表设置元表;如果要为其他类型的值设置元表,则必须通过C代码或调试库完成。

Lua 提供了两个函数来操作元表:

  1. setmetatable(table,metatable) 对指定 table 设置元表(metatable),如果元表 (metatable) 中存在 __metatable 键值,setmetatable 会失败
  2. getmetatable(table) 返回对象的元表 (metatable)

一个表可以成为任意值的元表;一组相关的表也可以共享一个描述了它们共同行为的通用元表;一个表还可以成为它自己的元表,用于描述其自身特有的行为。总之,任何配置都是合法的。

mytable = {name="zhangsan"}           -- 定义一个普通表 
mymetatable = {}                      -- 定义一个普通表作为元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表
getmetatable(mytable)                 -- 返回 mymetatable

-- 以上等价于下面这种简略写法
mytable = setmetatable({name="zhangsan"},{})

元方法

__index

Lua 语言中的 __index 字段是常用的表相关的元方法。如果 __index 字段对应的值是另一个表,那么当通过某个键来访问表时,这个键不存在,Lua 就会寻找该此表对应的元表中的 __index 键。也就会去另一 表中查找相应的键值。

Myable = { age = 17 }
-- 定义一个空表
t = {}

-- 给t设置元表
setmetatable(t,{__index = Myable})
print(t.age)  -- 17

如果 __index字段值是一个函数,那么 Lua 就会调用那个函数,表和键会作为参数传递给函数。当访问一个表中不存在的字段时会得到nil。实际上,这些访问会引发解释器查找一个名为__index的元方法。如果没有这个元方法,结果就是nil;否则,则由这个元方法来提供最终结果。

mytable = setmetatable({name="张三"}, 
    {
    __index = function(mytable, key)
        if key == "address" then
            return "my value"
        else
            return "not exist"
        end
    end
    })

print(mytable.name)  -- 张三
print(mytable.age)   -- not exist

这里,我们是可以利用元表的 __index 字段来模拟实现面向对象继承特性。

__newindex

元方法__newindex__index类似,不同之处在于前者用于表的更新而后者用于表的查询。当对一个表中不存在的索引赋值时,解释器就会查找__newindex元方法,如果这个元方法存在,那么解释器就调用它而不执行赋值。像元方法__index一样,如果这个元方法是一个表,解释器就在此表中执行赋值,而不是在原始的表中进行赋值。

利用这个元方法,我们可以很容易创建一个只读的表,只需要对更新操作并抛出异常即可。

__add

这里,我们通过设置元表的 __add 字段,即可实现两个表的加法运算。类似于操作符重载了。

  mytable = setmetatable({ 1, 3, 5 }, {
    __add = function(mytable, newtable)
                for k,v in ipairs(newtable) do
                    table.insert(mytable, v)
                end
                return mytable
           end})

  secondtable = {7,11,13}

  mytable = mytable + secondtable
  for k,v in ipairs(mytable) do
    print(v)
  end

元表可用的操作符字段

模式 描述
__add 对应的运算符 ‘+’
__sub 对应的运算符 ‘-’
__mul 对应的运算符 ‘*’
__div 对应的运算符 ‘/’
__mod 对应的运算符 ‘%’
__unm 对应的运算符 ‘-’
__concat 对应的运算符 ‘…’
__eq 对应的运算符 ‘==’
__lt 对应的运算符 ‘<’
__le 对应的运算符 ‘<=’

__call

元表字段__call 用于把表变量名当方法调用时的处理。

sum = setmetatable({10,28}, {
  __call = function(mytable, newtable)
    local s = 0
    for k,v in ipairs(mytable) do
        s = s + v
    end

    for k,v in ipairs(newtable) do
      s = s + v
    end
    return s
  end
})

table2 = {1,3,5}
print(sum(table2)) -- 返回两个表元素相加的总和

__tostring

修改表的打印输出行为

tb1 = {"lua","dart","go","rust"}

tb1 = setmetatable(tb1,{
  __tostring = function(mytable)
    s = "{"
    for k, v in pairs(mytable) do
        s = s..v.." ,"
      if k == #mytable then
        s = s..v.."}"
      end
    end
    return s
  end
})

print(tb1)

模块与包

模块类似于一个封装库,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

从用户观点来看,一个模块(module)就是一些代码(要么是Lua语言编写的,要么是C语言编写的),这些代码可以通过函数require加载,然后创建和返回一个表。这个表就像是某种命名空间,其中定义的内容是模块中导出的东西,比如函数和常量。

自定义一个名为 mymodule 的模块 mymodule.lua

mymodule = {}

-- 定义一个常量
mymodule.constant = "这是一个模块常量"

-- 定义一个函数
function mymodule.hello()
    print("Hello World!\n")
end

-- 定义一个私有函数
local function pfunc()
    print("这是一个定义在 mymodule 模块内的私有函数")
end

-- 定义一个公开函数调用 私有函数 pfunc
function mymodule.call_func()
    pfunc()
end

-- 返回模块
return mymodule

-- 模块定义完成

模块的本质就是定义一个 。 因此可以像操作调用表里的元素那样来操作调用模块里的常量或函数

-- 加载上面定义的模块
require("mymodule")

print(mymodule.constant)
mymodule.call_func()

也可以给模块起一个别名再调用

-- 定义一个别名 m
local m = require("mymodule")

-- 通过别名调用常量 
print(m.constant)
-- 通过别名调用函数
m.call_func()

通常函数只有一个字符串类型参数时,会省略括号,因此加载模块的代码会写作local m = require "mymodule"

模块加载机制

require 函数有着自己的文件路径加载策略,它会尝试从 Lua 文件或 C程序库中搜索并加载模块。其用于搜索 Lua 文件的路径是存放在全局变量 package.path 中。

当 Lua 启动后,会以环境变量LUA_PATH的值来初始这个全局变量。 如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。 当然,如果没有LUA_PATH这个环境变量,也可以自定义配置。

LUA_PATH文件路径以分号 ; 分隔,最后的 2 个分号;; 表示新加的路径后面加上原来的默认路径。例如:

export LUA_PATH="~/lua/?.lua;;"

如果找到目标文件,则会调用package.loadfile函数来加载模块。 否则,就会去找 C 库。搜索 C 程序库的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始化的。搜索 C 库的策略跟上面的一样,只是搜索的文件名由 .lua 换成了 .so.dll 。 如果找到,那么 require 函数就会通过package.loadlib来加载它。

Lua的面向对象

对象由属性和方法组成。Lua中最基本的结构是表,Lua可以使用表来描述对象的属性和方法,那么 Lua 中的类可以通过表+函数模拟出来,而继承,则可以通过元表模拟。

-- 使用 table 定义类
Rectangle = {area = 0, length = 0, breadth = 0}

--  类的方法 new
function Rectangle:new (o,length,breadth)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  self.length = length or 0
  self.breadth = breadth or 0
  self.area = length*breadth;
  return o
end

-- 类的方法 printArea
function Rectangle:printArea ()
  print("矩形面积: ",self.area)
end


r = Rectangle:new(nil,6,8)
print(r.length)  -- 点号访问类的属性
r:printArea()    -- 冒号访问类的成员函数

模拟继承实例:

-- 定义父类
Shape = {area = 0}

-- 定义类方法 new
function Shape:new (o,side)
  o = o or {}
  setmetatable(o, self)
  self.__index = self
  side = side or 0
  self.area = side*side;
  return o
end

-- 定义类方法 printArea
function Shape:printArea ()
  print("面积为: ",self.area)
end

-- 定义类 Square 继承 Shape
Square = Shape:new()
function Square:new (o,side)
  o = o or Shape:new(o,side)
  setmetatable(o, self)
  self.__index = self
  return o
end

-- 创建对象
mysquare = Square:new(nil,16)
mysquare:printArea()

协程

协程(coroutine) 与线程类似,拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协程共享全局变量和其它大部分东西。线程与协程的主要区别在于:

一个具有多个线程的程序可以同时运行几个线程,而协程却需要彼此协作的运行。在任一指定时刻只有一个协程在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。协程有点类似同步的多线程,在等待同一个线程锁的几个线程类似于协程。

Lua语言中协程相关的所有函数都被放在表coroutine中。函数create用于创建新协程,该函数只有一个参数,即协程要执行的代码(协程体,即一个函数)。create返回一个thread类型的值,即新协程。通常,函数create的参数是一个匿名函数,例如:

co = coroutine.create(
    function()
        print("hello")
    end
)

print(type(co))

一个协程有四种状态:

  • 挂起(suspended)

  • 运行(running)

  • 正常(normal)

  • 死亡(dead)

可以通过函数coroutine.status来检查协程的状态:

print(coroutine.status(co))

注意,当一个协程被创建时,它处于挂起状态,即协程不会在被创建时自动运行。函数coroutine.resume用于启动或再次启动一个协程的执行,并将其状态由挂起改为运行:

coroutine.resume(co) 

如果在交互命令行模式下运行上述代码,最好在最后一行加上一个分号来阻止输出函数resume的返回值。

协程的真正强大之处在于函数yield,该函数可以让一个运行中的协程挂起自己,然后在后续恢复运行。例下例:

co2 = coroutine.create(
    function()
        for i=1,10 do
            print(i)
            coroutine.yield()
        end
    end
)

coroutine.resume(co2) -- 1
coroutine.resume(co2) -- 2
coroutine.resume(co2) -- 3

首先创建了一个协程,调用resume函数开始运行协程,协程进入了一个循环,循环中代码正常执行,直到遇到第一个yield,协程会挂起,再次调用resume函数,则继续执行循环中的代码,直到遇到yield后挂起。不断调用resume,重复这个过程,在最后一次调用resume时,协程体执行完毕(超出for循环的条件,for循环退出)并返回,不输出任何数据。如果我们试图再次resume它,则resume函数将返回false和一条错误信息。

需要注意,只有当我们唤醒(调用resume)协程时,函数yield才会最终返回,这点很重要。来看一个有参数有返回值的示例:

co3 = coroutine.create(
    function (a , b)
        local sum = a + b
        coroutine.yield(sum) 
    end
)

-- 通过resume函数来传入协程体需要的两个参数a、b
-- 协程体若有返回值,则传入yield函数返回。在外部,则是通过resume函数来接收该返回值
-- 需要注意,resume函数的第一个返回值是布尔值,表示协程是否调用成功,接下来第二个返回值才是协程体返回的具体值
print(coroutine.resume(co3,2,3))

实现生产者-消费者模型

这里,我们使用lua的协程来实现一个经典的生成者消费者问题

local new_productor

-- 生产者
function productor()
     local i = 0
     while true do
          i = i + 1
          send(i)     -- 将生产的东西发给消费者
     end
end

-- 消费者
function consumer()
     while true do
          local i = receive()     -- 接收生产者的东西
          print(i)
     end
end

function receive()
     local status, value = coroutine.resume(new_productor)
     return value
end

function send(x)
     coroutine.yield(x)     -- x表示需要发送的值,值返回以后,就挂起该协程
end

-- 启动程序
new_productor = coroutine.create(productor)
consumer()

文件与 I/O

Lua的 I/O 库主要用于读取和处理文件。读写文件时分为 简单模式(和C一样)和 完全模式

  • 简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
  • 完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法

简单模式使用标准的 I/O 或使用一个当前输入文件和一个当前输出文件

-- 以只读方式打开文件
file = io.open("test.lua", "r")
-- 设置默认输入文件
io.input(file)

-- 打印文件第一行
print(io.read())
-- 关闭打开的文件
io.close(file)

----------------------------------------------

-- 以追加的方式打开只写文件
file = io.open("test.lua", "a")
-- 设置默认输出文件
io.output(file)

-- 在文件最后一行写入字符串"end..."
io.write("end...")
-- 关闭打开的文件
io.close(file)

简单模式可做一些简单文件操作,但是在进行一些高级的文件操作时,就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。

-- 以只读方式打开文件
file = io.open("test.lua", "r")
-- 打印文件第一行
print(file:read())
-- 关闭打开的文件
file:close()

----------------------------------------------

-- 以追加方式打开只写文件
file = io.open("test.lua", "a")
-- 在文件最后一行写入字符串
file:write("--test")

-- 关闭打开的文件
file:close()

注意,完全模式使用file:方式调用函数,而不是io.的方式。

Lua打开文件操作的函数原型如下:

file = io.open (filename [, mode])

其中参数mode有许多可选的值:

模式 描述
r 以只读方式打开文件,文件必须存在
w 以只写方式打开文件,若文件存在则以新的空文件覆盖;若文件不存在则新建文件
a 以追加的方式打开只写文件。若文件不存在,则新建文件;若文件存在,写入的数据会被追加到末尾(EOF符保留)
r+ 以可读写方式打开文件,文件必须存在
w+ 打开可读写文件,若文件存在则以新的空文件覆盖;若文件不存在则新建文件
a+ a模式类似,但文件可读可写
b 以二进制模式打开
+ 表示对文件既可读也可写

其他的一些io 方法:

函数 描述
io.tmpfile() 返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除
io.type(file) 检测file是否一个可用的文件句柄
io.flush() 将缓冲中的所有数据写入文件
io.lines(optional file name) 返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,但不关闭文件

Lua 15分钟快速上手(上)


关注公众号:编程之路从0到1
编程之路从0到1

或关注博主的视频网校

云课堂

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Lua 15分钟快速上手(下) 的相关文章

  • 如何更改 Flutter 中的默认字体系列

    如何更改应用程序的每个文本以使用特定字体 我可以使用以下命令单独更改它们TextStyle 但如何让我的应用程序默认使用特定字体 你能告诉我怎么做吗 您可以按照以下步骤更改 Flutter 应用程序的默认字体系列 1 将字体文件添加到项目文
  • 颤振预览图标在代码完成时显示损坏的资源图像

    当我第一次安装 flutter 和 dart 扩展时 图标预览工作正常 但是当我在没有 wi fi 的环境中开发时 图标预览损坏了 不确定这是问题所在 我尝试重新安装所有与 flutter 和 dart 相关的扩展 但问题仍然存在 如果有任
  • 没有脚手架的 DefaultTabController?

    我正在尝试使用DefaultTabController在一些小部件的中间 所以我的TabBar不能在AppBar并且必须关闭一些小部件 所以我的问题是当我使用时TabBarView它崩溃了 这是一个 Flutter 示例的示例 但没有找到如
  • Android Gradle 问题 - Flutter / Dart

    我的 Gradle 同步有问题 我使用 IntelliJ 和 Android Studio 构建 Flutter Dart 应用程序 我添加了 2 个新的依赖项 现在 Gradle 出现了问题 在 Android Studio 中一切正常
  • 如何在flutter项目中使用http拦截器?

    我必须向我的所有 Api 添加标头 有人告诉我为此使用 http 拦截器 但我无法理解如何做到这一点 因为我是颤振的新手 谁能帮我举个例子吗 您可以使用http 拦截器 https pub dev packages http interce
  • NestedScrollView 与 ListView 中的粘性选项卡

    布局按预期工作 但以下情况除外 当我滚动一页时 第二页也会滚动 没有那么多 但足以掩盖第一个项目 我可以想象它与 NestedScrollView 有关 但我不知道如何继续 import package flutter material d
  • Flutter - 构建失败并出现异常

    当我启动我的应用程序时 我收到此错误消息 自上次运行以来我没有进行任何更改 当时一切都很好 有人知道如何解决这个问题吗 谢谢 FAILURE Build failed with an exception 什么地方出了错 无法确定任务 app
  • 谷歌地图颤动检查点是否在多边形内

    我正在使用 google maps flutter 插件开发 flutter 项目 我想检查用户位置是否位于我在地图上创建的多边形内 有一个简单的方法使用 JavaScript api con tainsLocation 方法 但对于 fl
  • 如何将额外的文本添加到颤振谷歌地图自定义标记中?

    问题是如何将自定义谷歌地图标记上的文本重叠与代表车辆登记号的文本融合在一起 我尝试使用此方法将文本叠加在图标上 生成器 上下文 gt 但根本不被认可 class MapsDemo extends StatefulWidget overrid
  • Flutter Firestore - 如何从文档字段中的文档引用获取数据?

    我正在构建一个具有不同问题类型的自学应用程序 现在 其中一个问题有一个包含文档参考列表的字段 在 Flutter 中 我有以下代码 Query
  • 用颤动画布在形状上切一个洞

    如何使用颤动画布在形状上 切一个洞 我有一组相当复杂的形状 看起来像现实世界的物体 该物体上有一个圆角矩形形状的孔 我真的很想从形状中减去 RRect 但我找不到任何有关如何执行此操作的信息 canvas clipRRect myRRect
  • Flutter:将字符串转换为 Map

    我正在使用 SQFlite 在本地存储数据 我有一个表 其中有一个名为 json 的字段 该字段的类型为 TEXT 并存储转换为字符串的 json 例如 name Eduardo Age 23 性别男 到目前为止 一切正常 但随后我需要从数
  • 在 dart 中使用括号表示法访问对象的属性

    我尝试执行以下操作 var properties height width for var prop in properties div style prop otherdiv style prop 但是 dart 似乎不接受这种括号表示法
  • 如何在 Dart 分析器/source-gen 中从某些元素获取 AstNode?

    我在用着source gen解析一些Dart文件 通过Dartanalyzer 我正在延长GeneratorForAnnotation lt gt 以及重写方法FutureOr
  • 在 Flutter 中渲染小部件之前,如何等待异步函数完成执行

    On my main dart文件中 我想检查用户是否已登录 以便将他定向到适当的屏幕 我正在使用 SharedPrefence 来存储 Firebase 中的用户详细信息 如何告诉我的函数等到 SharedPreference 异步函数完
  • Lua C API:初始化结构体 C 中的变量矩阵

    我正在尝试使用 Lua C API 创建一个用户数据 并在其中关联一个元表 我将在其中收集矩阵 我无法得到的是如何将初始化矩阵的每个分量设置为零 我按照我的描述编译我的 Lua 模块 C 代码here https stackoverflow
  • LuaJ 导入 Lua 方法

    我正在使用 LuaJ 并且我有一个 lua文件充满了一堆函数 如何通过 LuaJ 导入这些函数以在 Java 中使用 一种选择是将文件编译为 Java 代码并导入它 另一种方法是使用可嵌入解释器直接从 Java 代码中调用 Lua 文件 E
  • 关闭 Löve2D 中的抗锯齿功能

    我在用着L ve2D http love2d org用于编写一个小游戏 L ve2D 是 Lua 的开源游戏引擎 我遇到的问题是 当您在非整数位置绘制精灵时 某些抗锯齿过滤器会自动应用于精灵 love graphics draw sprit
  • 如何实现类似预编译指令的功能

    我正在开发一个 Angular 应用程序 建议对生产中运行的许多东西使用生成的代码 即模板缓存 表达式缓存和静态 DI 注入器 目前没有在不同构建配置之间切换的好方法 因此我使用推荐的模式here https github com angu
  • Cloud Functions,删除Firestore SubCollections,是否需要AdminToken?

    我正在尝试构建可调用的云函数 当用户删除帖子时 它也会尝试删除评论 这是帖子的子集合 所以我看到了这个例子并像文档示例一样实现 const admin require firebase admin const firebase tools

随机推荐

  • TypeScript中any、unknown、never和void有什么区别?

    any 任意类型的变量 unknown 表示未知类型 unknown与any类似 但使用前必须进行断言或守卫 never 永不存在的值的类型 void 无任何类型 没有类型 用于函数时 never表示函数用于执行不到返回值那一步 抛出异常或
  • 植物图像识别python_python实现图像识别功能

    本文实例为大家分享了python实现图像识别的具体代码 供大家参考 具体内容如下 usr bin env python from PIL import Image import pytesseract url img denggao jpe
  • 什么是IDS?

    1 什么是IDS IDS是 入侵检测系统 intrusion detection system 简称 IDS 是一种对网络传输进行即时监视 在发现可疑传输时发出警报或者采取主动反应措施的网络安全设备 它与其他网络安全设备的不同之处便在于 I
  • Swagger-使用教程(详细)

    Swagger Swagger官网 https swagger io Swagger是一款 RESTful 风格的 Web 服务框架 那么问题来了 什么是RESTful RESTFUL是一种网络应用程序的设计风格和开发方式 基于HTTP 可
  • ComSec HW6 Hash

    11 1 安全 Hash 函数需要具有那些特性 H能用于任何大小的数据分组 H产生定长输出 对任意给定的x H x 要相对易于计算 使得软硬件实现都实际可行 单向性 对任意给定的码y 寻求x使得H x y在计算上不可行 弱抗碰撞性 任意给定
  • Flink学习笔记(3)——Flink部署

    目录 一 Flink 部署 1 1 快速启动一个集群 1 1 1 环境配置 1 1 2 集群启动 1 1 3 向集群提交作业 1 2 部署模式 1 2 1 会话模式 1 2 2 单作业模式 Per Job Mode 1 2 3 应用模式 A
  • 什么是FPGA?为什么FPGA会如此重要?

    CPU GPU FPGA三者能力相加就是芯片的未来 很多粉丝问我 嵌入式方向中的FPGA怎么样 收入如何 前言 这个时候 一定会有抬杠青年说 我见过国内生产的FPGA芯片 还用过呢 通常遇到这一类质疑声 我一般都会说 你是对的 后来 要知道
  • Ubuntu firefox 上无法联网

    问题描述1 firefox 登录百度失败 解决方案 打开Firefox 点击右上角三条杠 进入 选项 点击 高级 切换到 网络 点击 连接设置 设置为 不使用代理 即可 如果还没能解决问题 请接着往下看 尝试ping www baidu c
  • Linux第三周作业

    Linux第三周作业 第三周作业 一 基础班 1 显示 etc目录下 以非字母开头 后面跟了一个字母以及其它任意长度任意字符的文件或目录 2 复制 etc目录下所有以p开头 以非数字结尾的文件或目录到 tmp mytest1目录中 3 将
  • impala查询转义问题

    select REGEXP REPLACE 佰分贰拾 深圳 品牌管理有限公司 然后 SELECT vendor full name REGEXP REPLACE vendor full name FROM odsmdmdata sms ve
  • 面试 - Redis 多路复用原理

    大家都知道redis是单进程而且快 那你知道为什么吗 面试中我只能答出多路复用 但具体的原理又不知道了 很尴尬 不过也很欣慰 从一次又一次的失败中总结经验弥补不足 事实上有一定经验的人知识如果不够深已经不是什么问题了 不过还是得补下这个课
  • Python 图像处理之 JPEG 格式

    Python 图像处理之 JPEG 格式 JPEG Joint Photographic Experts Group 是一种常见的图像压缩格式 在数字图像处理 图像传输等领域得到广泛应用 Python 内置的 PIL 库提供了对 JPEG
  • Qt在软件运行过程中改变一个控件的样式

    需求 在软件运行过程中改变一个控件的样式 思路 使用qss的属性选择器 在qss文件中分别对控件的某个属性的不同属性值设置样式 当需要修改控件样式时 修改控件属性的值 并重新加载该控件的样式表 如何修改控件属性的值 可以先了解一下Qt的属性
  • IntelliJ IDEA插件系列:四大炫酷神器你值得拥有

    拥有了这四款插件 你就比别人领先一步 你的界面独一无二 1 Mario Progress Bar 这是基于 IJ 的 IDE 的 Mario 进度条 基于 Dmitry Batkovitch 的 Nyan 进度条 它展示了马里奥 Mario
  • 软件测试人员该学习 Python 的七个理由

    对于一个软件测试工程师来说 选哪一门语言来入手编程一直是件非常纠结的事情 当然立志做一辈子功能测试的人除外 值得庆幸的是 专门介绍软件 工具及网站服务的技术Blog上CarlCheo绘制了一张图表 告诉你该怎么开始伟大的码农航道 大多数好的
  • (六)练习:饮料自动售货机

    1 找出所有的原因 输入 并编号 1 投币5角 2 投币1元 3 按下 橙汁 按钮 4 按下 啤酒 按钮 2 找出所有的结果 输出 并编号 注意 不能写购买成功 饮料送出 因为若买橙汁 则应该送出橙汁 送出啤酒是不对的 若只写找零 则在画因
  • mybatis:mybatis再总结

    1 什么是mybatis 优点 缺点 适用场合 与Hibernate的对比 https www cnblogs com zhai1997 p 12527689 html 2 和 的区别是什么 是预编译处理 是字符串替换 将传入的数据都当成一
  • Pytorch基础学习(第四章-Pytorch损失优化)

    课程一览表 目录 一 权值初始化 1 梯度消失与爆炸 2 Xavier方法与kaiming方法
  • unity 设置layer 使碰撞器不碰撞

    做游戏时 有时候需要让同一个地图的两个敌人不互相碰撞 但是两个人都有碰撞器 能站在地上 这个功能是如何实现的呢 答案就是设置layer 当点击Hierarchy窗口中的某个对象时 在Inspector窗口就可以看见Layer选项 如图 你可
  • Lua 15分钟快速上手(下)

    本系列相关文章 Flutter 热更新及动态UI生成 Lua 15分钟快速上手 上 Lua 15分钟快速上手 下 Lua与C语言的互相调用 LuaDardo中Dart与Lua的相互调用 进阶语法篇 迭代器 迭代器 iterator 是一种可