精华内容
下载资源
问答
  • 六、双击,在输入框右侧可以选择本FB数据类型建立的静态变量名,选择其中一个就可以,也可以直接在输入框中输入变量名,软件有联想功能,只有输入前几个字母会自动匹配(如图6、图7),选择需要的变量名就可以了(如...

    我在程序中已创建军了一个“ FB1 “ 然后又创建军了一个 ”FB2 “  ,然后在 “FB2” 的静态变量 Static 下创建了变量名**,数扭类型为 “ FB1 “ 。  请问再向下怎么做? 是在FB2先调用FB1,然后再在主程序中调用FB2吗? 还是其它方法,希望能写详细点。多谢,在实例更好。

    最佳答案

    一、就像你说的线建一个FB1,然后建一个FB2,在FB1中的静态变量下创建几个变量名(如图1);

    二、在FB1中调用FB2,此时会弹出对话框让你选择单个实例或多重背景(如图2);

    三、在下拉中可以选择在静态变量中建的变量名(如图3);

    四、选择其中一个就可以了(如图4);

    五、假如在上一步你选择了取消,那么也没关系(如图5);

    六、双击??>,在输入框右侧可以选择本FB数据类型建立的静态变量名,选择其中一个就可以,也可以直接在输入框中输入变量名,软件有联想功能,只有输入前几个字母会自动匹配(如图6、图7),选择需要的变量名就可以了(如图8)

    希望对你有用。

    图片说明:

    e2d118a8b32424e31df2b00b30a8ca6f.png  

    b48562883c6c31538e5fa5c298b0c6d3.png  

    5722e940c431d3926ce1fd7965002588.png  

    9a6620cbf432c076526ac199b8e9910b.png  

    c50701f2caf48422a02773ff3aca5f59.png  

    9262b12dc53765659d63a9c3eaaea302.png  

    2107f8bc05c449725836ba7ecb349fc7.png  

    8d32f8f98ba661f9da47febe27a8fd8b.png

    提问者对于答案的评价:

    讲得详细,感谢谢

    专家置评

    已阅,最佳答案正确。

    展开全文
  • 继续讲VLOOKUP函数,今日的讲的是第四个专题,多值查找的实现。到这篇,此函数的讲解将将告一段落。什么是多值的查找呢?通常情况下,我们在使用VLOOKUP时都是指查找到的是一个值,对于多个值,无能为力了,即使是...

    继续讲VLOOKUP函数,今日的讲的是第四个专题,多值查找的实现。到这篇,此函数的讲解将将告一段落。什么是多值的查找呢?通常情况下,我们在使用VLOOKUP时都是指查找到的是一个值,对于多个值,无能为力了,即使是模糊查找,也要出是排序后查找到一个和要查找的值最接近的值。

    那么有没有办法实现多个值的查找呢?当然能。在这个专业面对广大职场人群的平台上,你会看到这个函数不一样的应用。包括你不敢想象的。在很多的理论中都在介绍VLOOKUP的单值查找结果,这这里你会看到多值查找结果的方案。

    如下面的例子:

    有多个甲1,年龄分别不一样,如何能查找到各自的年龄呢?

    分析:经过前面的几篇VLOOKUP的文章,我们也有这样一个思路,我们在实现复杂的查找时,努力的方向是重构一个新的查找内容和查找的区域。要想实现多项查找,我们可以依然借鉴这样的思路。可以这样来实现:对查找的内容进行编号,第一个出现的是后面连接1,第二个出现的连接2……,好,就按照这样的思路来一步一步的实现我们的目标。

    我们先看一下B19中输入的公式:{=VLOOKUP(A$19&ROW(A1),IF({1,0},$A$2:$A$16&COUNTIF(INDIRECT("A2:A"&ROW($2:$16)),$A$19),$C$2:$C$16),2,)}

    对于部分朋友而言,上面的公式是不是如同天书一样?不要急,和我一起来慢慢分析,分析明白了,也就能学会了。

    1. A$19&ROW(A1) 会形成“甲11”这样的字符,当向下填充B20 ,B21,中时会形成“甲12”“甲13”等字符,这就实现了我们的既定目标“第一个出现的是后面连接1,第二个出现的连接2…….”

    2. 给所有的甲1进行编号。要想生成编号,就需要生成一个不断扩充的区域(INDIRECT("A2:A"&ROW($2:$16)),然后在这个逐行扩充的区域内统计“甲1”的个数,在连接上$C$2:$C$19后就可以对所有的甲1进行编号了。

    3、IF({1,0}把编号后的B列和C组重构成一个两列数组。在此数字中查找甲11,甲12 的值。

    下面我把这个函数的实现过程中关键步骤的结果写给大家:

    公式:{=VLOOKUP(A$19&ROW(A1),IF({1,0},$A$2:$A$16&COUNTIF(INDIRECT("A2:A"&ROW($2:$16)),$A$19),$C$2:$C$16),2,)}

    运算关键步骤:黑体字描述了每步骤的变化。

    步骤1:=VLOOKUP(“甲11”,IF({1,0},$A$2:$A$16&COUNTIF(INDIRECT("A2:A"&ROW($2:$16)),$A$19),$C$2:$C$16),2,)

    步骤2:=VLOOKUP(“甲11”,IF({1,0},{“甲1”;“甲2”;“甲3”; “甲4” ;“甲5” ;“甲6” ;甲1”;“甲2”;“甲3”; “甲4” ;“甲5” ;“甲6” ;甲1”;“甲14”;“甲15”}&COUNTIF(INDIRECT("A2:A"&ROW($2:$16)),$A$19),$C$2:$C$16),2,)

    步骤3:=VLOOKUP(“甲11”,IF({1,0},{“甲1”;“甲2”;“甲3”; “甲4” ;“甲5” ;“甲6” ;甲1”;“甲2”;“甲3”; “甲4” ;“甲5” ;“甲6” ;甲1”;“甲14”;“甲15”}&COUNTIF(INDIRECT({"A2:A2";"A2:A3";"A2:A4";"A2:A5";"A2:A6";"A2:A7";"A2:A8";"A2:A9";"A2:A10";"A2:A11";"A2:A12";"A2:A13";"A2:A14";"A2:A15";"A2:A16"}),$A$19),$C$2:$C$16),2,)

    步骤4:=VLOOKUP(“甲11”,IF({1,0},{“甲1”;“甲2”;“甲3”; “甲4” ;“甲5” ;“甲6” ;甲1”;“甲2”;“甲3”; “甲4” ;“甲5” ;“甲6” ;甲1”;“甲14”;“甲15”}& {1;1;1;1;1;1;2;2;2;2;2;2;3;3;3},$C$2:$C$19),2,)

    步骤5:=VLOOKUP(“甲11”,IF({1,0},{“甲11”;“甲21”;“甲31”; “甲41” ;“甲51” ;“甲61” ;甲12”;“甲22”;“甲32”; “甲42” ;“甲52” ;“甲62” ;甲13”;“甲143”;“甲153”},$C$2:$C$16),2,)

    步骤6:=VLOOKUP(“甲11”,IF({1,0},{“甲11”,170;“甲21”,160;“甲31”.150; “甲41”,140 ;“甲51”,130 ;“甲61”.120 ;甲12”,110;“甲22”,100;“甲32”,90; “甲42”,100 ;“甲52”,110 ;“甲62” ,120;甲13”,130;“甲143”,140;“甲153”,150},2,)

    步骤7:= 170

    以上步骤是关键的几个步骤,如果不是很明白,请再次阅读我的数组运算的文章,或者和我联络再次讲解。

    下面看最后的结果:

    共有三个值被找出来了,结果和预期的一致。

    今日内容回向:

    1 如何利用VLOOKUP求出多值的查询?

    2 利用VLOOKUP进行多值查询的思路是怎么样的?

    3 是否还清楚的记得数组的表示和运算?

    分享成果,随喜正能量。

    展开全文
  • 二、模式匹配match 1. 概念 2. 示例 三、偏函数 1. 概念 2. 示例 四、样例类 1. 概念 2. 示例 一、trait特性 1. 概念 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。与接口不同的是...

     前言

            此系列为scala学习文章,适用于为学spark而学习scala

            视频参考地址:Scala快速入门(适合为学Spark学习Scala的同学)

            系列文章如下:

            1. Scala学习01——Scala介绍

            2. Scala学习02——Scala类和对象

            3. Scala学习03——基础语法

            4. Scala学习04——Scala方法与函数

            5. Scala学习05——Scala集合

            6. Scala学习06——trait特性、模式匹配、偏函数、样例类

            7. Scala学习07——隐式转换

            资料下载地址:Scala课件资料.docx

    目录

    一、trait特性

    1. 概念

    2. 示例

    二、模式匹配match

    1. 概念

    2. 示例

    三、偏函数

    1. 概念

    2. 示例

    四、样例类

    1. 概念

    2. 示例


    一、trait特性

    1. 概念

            Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。与接口不同的是,它还可以定义属性和方法的实现。一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait

    • 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
    • trait中不可以传参数
    • trait中的方法可以实现,也可以不实现,若不实现,则类继承时要实现trait中未实现的方法
    • 一个类继承多个trait时,第一个关键字使用extends,之后使用with

    2. 示例

    (1)trait中带属性带方法实现

    trait Read {
      val readType = "Read"
      val gender = "m"
      def read(name:String){
    	println(name+" is reading")
      }
    }
    
    trait Listen {
      val listenType = "Listen"
      val gender = "m"
      def listen(name:String){
    	println(name + " is listenning")
      }
    }
    //Person类继承 read和listen 
    class Person() extends Read with Listen{
      override val gender = "f"
    }
    /*
    zhangsan is reading
    lisi is listenning
    Listen
    Read
    f
    */
    object test {
      def main(args: Array[String]): Unit = {
        val person = new Person()
        person.read("zhangsan")
        person.listen("lisi")
        println(person.listenType)
        println(person.readType)
        println(person.gender)
      }
    }

    (2)trait中带方法不实现

    object Lesson_Trait2 {
      def main(args: Array[String]): Unit = {
        val p1 = new Point(1,2)
        val p2 = new Point(1,3)
        println(p1.isEqule(p2))
        println(p1.isNotEqule(p2))
      }
    }
    
    trait Equle{
      def isEqule(x:Any) :Boolean 
      def isNotEqule(x : Any)  = {
        !isEqule(x)
      }
    }
    
    class Point(x:Int, y:Int) extends Equle {
      val xx = x
      val yy = y
    
      def isEqule(p:Any) = {
        //判断是否为point实例,若为则作为point实例则取出xx,判断是否等于 this.xx(p1.xx)
        p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx
      }
    }

    二、模式匹配match

    1. 概念

            Scala 提供了强大的模式匹配机制,应用也非常广泛。一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。

    • 模式匹配不仅可以匹配值还可以匹配类型
    • 从上到下顺序匹配,如果匹配到则不再往下匹配
    • 都匹配不上时,会匹配到case _ ,相当于default
    • match 的最外面的”{ }”可以去掉看成一个语句

    2. 示例

    object Lesson_Match {
      def main(args: Array[String]): Unit = {
        val tuple = Tuple6(1,2,3f,4,"abc",55d)
        val tupleIterator = tuple.productIterator
        while(tupleIterator.hasNext){
          matchTest(tupleIterator.next())
        }
        
      }
    
      def matchTest(x:Any) ={
        x match {
          case x:Int=> println("type is Int")
          case 1 => println("result is 1")
          case 2 => println("result is 2")
          case 3=> println("result is 3")
          case 4 => println("result is 4")
          case x:String => println("type is String")
    //      case x :Double => println("type is Double")
          case _ => println("no match")
        }
      }
    }

    三、偏函数

    1. 概念

            如果一个方法中没有match 只有case,这个函数可以定义成PartialFunction偏函数。偏函数定义时,不能使用括号传参,默认定义PartialFunction中传入一个值,匹配上了对应的case,返回一个值,只能匹配同种类型

    • PartialFunction[匹配的类型,匹配上传出的类型]
    • 相当于java的 switch....case,只能匹配一种类型

    2. 示例

    /**
      * 一个函数中只有case 没有match ,可以定义成PartailFunction 偏函数
      */
    object Lesson_PartialFunction {
      def MyTest : PartialFunction[String,String] = {
        case "scala" =>{"scala"}
        case "hello"=>{"hello"}
        case _=> {"no  match ..."}
      }
      def main(args: Array[String]): Unit = {
          println(MyTest("scala"))
      }
    }
    

    四、样例类

    1. 概念

            使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。

    • 样例类默认帮你实现了toString,equals,copy和hashCode等方法。
    • 样例类可以new, 也可以不用new
    • 当一个类被定义成为case类后,Scala会自动帮你创建一个伴生对象并帮你实现了apply, unapply,setter, getter 和toString,equals,copy和hashCode等方法

    2. 示例

    case class Person1(name:String,age:Int)
    
    object Lesson_CaseClass {
      def main(args: Array[String]): Unit = {
        val p1 = new Person1("zhangsan",10)
        val p2 = Person1("lisi",20)
        val p3 = Person1("wangwu",30)
        
        val list = List(p1,p2,p3)
        list.foreach { x => {
          x match {
            case Person1("zhangsan",10) => println("zhangsan")
            case Person1("lisi",20) => println("lisi")
            case _ => println("no match")
          }
        } }
        
      }
    }
    

    展开全文
  • 6 函数

    2021-05-22 04:02:16
    在 Lua 语言中,函数是对语句和表达式进行抽象的主要方式。函数既可以用于完成某种特定任务或子例程,也可以只是进行一些计算然后返回计算结果。在前一种情况下,我们将一句函数调用视为一条语句;而在后一种情况下...

    在 Lua 语言中,函数是对语句和表达式进行抽象的主要方式。函数既可以用于完成某种特定任务或子例程,也可以只是进行一些计算然后返回计算结果。在前一种情况下,我们将一句函数调用视为一条语句;而在后一种情况下,我们则将函数调用视为表达式:

    print(8 * 9)

    a = math.sin(3) + math.cos(10)

    print(os.date())

    无论哪种情况,函数调用时都需要使用一对圆括号把参数列表括起来。即使被调用的函数不需要参数,也需要一对空括号 ()。对于这个规则,唯一的例外就是,当函数有且只有一个参数,且该参数是字符串常量或表构造器时,括号是可选的:

    print "hello world" print("hello world")

    dofile 'a.lua' dofile('a.lua')

    print [[amulti-line print([[amulti-line

    message]] message]])

    f{x = 10, y =20} f({x = 10, y = 20})

    type{} type({})

    我不确定其他语言是否有这样的语法,但我使用 Lua 主要用于 Unity 中的热更新,所以,即使有这样可选的括号,我还是建议把括号带上,毕竟写代码不是指写给自己看,多为别人着想!

    Lua 语言也为面向对象风格的调用提供了一种特殊的语法,即冒号操作符。形如 o:foo(x)的表达式意为调用对象 o 的 foo 方法。在第 21 章中,我们会继续学习这种调用方式及面向对象编程。

    一个 Lua 程序既可以调用 Lua 语言编写的 函数,也可以调用 C 语言编写的函数。一般来说,我们选择使用 C 语言编写的函数来实现对性能要求更高,或不容易直接通过 Lua 语言进行操作的操作系统机制等。例如,Lua 语言标准库中所有的函数都是使用 C 语言编写的。不过,无论一个函数是用 Lua 语言编写的还是用 C 语言编写的,在调用它们时都没有任何区别。

    正如我们已经在其他示例中所看到的,Lua 语言中的函数定义的常见语法格式形如:

    function add(a)

    local sum = 0

    for i = 1, #a do

    sum = sum + a[i]

    end

    return sum

    end

    在这种语法中,一个函数定义具有一个函数名、一个参数组成的列表和由一组语句组成的函数体。参数的行为与局部变量的行为完全一致,相当于一个用函数调用时传入的值进行初始化的局部变量。

    调用函数时使用的参数个数可以与定义函数时使用的参数个数不一致。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

    虽然这种行为可能导致编程错误,但同样又是有用的,尤其是对于默认参数的情况。例如,考虑如下递增全局计数器的函数:

    function incCount(n)

    n = n or 1

    globalCounter = globalCounter + 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 = 1

    local m = a[mi]

    for i = 1, #a do

    if a[i] > m then

    mi = i; m = a[i]

    end

    end

    return m, mi

    end

    print(maximum({8, 10, 23, 12, 5})) --> 23 3

    Lua 语言根据函数的被调用情况调整返回值的数量。当函数被作为一条单独的语句调用时,其所有返回值都会被丢弃;当函数被作为表达式调用时,将只保留第一个返回值。只有当函数调用是一系列表达式中的最后一个表达式(或唯一一个表达式)时,其所有的返回值才能被获取到。这里所谓的“一系列表达式”在 Lua 中表现为 4 种情况:多重赋值、函数调用时传入的实参列表、表构造器和 return 语句。为了分别展示这几种情况,接下来举几个例子:

    function foo0() end

    function foo1() return "a" end

    function foo2() return "a", "b" end

    在多重赋值中,如果一个函数调用是一系列表达式中的最后一个(或是唯一一个)表达式,则该函数调用将产生尽可能多的返回值以匹配待赋值变量:

    x, y = foo2() --> x = "a", y = "b"

    x = foo2() --> x = "a", "b"被丢弃

    x, y, z = 10, foo2() --> x = 10, y = "a", z = "b"

    在多重赋值中,如果一个函数没有返回值或者返回值个数不够多,那么 Lua 语言会用 nil 来补充缺失的值:

    x, y = foo0() --> x = nil, y = nil

    x, y = foo1() --> x = "a", y = nil

    x, y, z = foo2() --> x = "a", y = "b", z = nil

    请注意,只有当函数调用是一系列表达式中的最后一个(或唯一一个)表达式时才能返回多值结果,否则只能返回一个结果:

    x, y = foo2(), 20 --> x = "a",y = 20

    x, y = foo0(), 20, 30 --> x = nil, y = 20

    x = foo0(), 20 --> x = nil (我自己补充一个)

    当一个函数调用是另一个函数调用的最后一个(或者唯一一个)实参时,第一个函数的所有返回值都会被作为实参传给第二个函数。我们已经见到过很多这样的代码结构,例如函数print能够接受可变数量的参数,所以print(g())会打印出 g 返回的所有结果。

    print(foo0()) --> (无结果)

    print(foo1()) --> a

    print(foo2()) --> a b

    print(foo2(), 1) --> a 1

    print(foo2() .. "x") --> ax

    print("x" .. foo2()) --> xa (我自己补充一个)

    当在表达式中调用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} --> t[1] = nil, t[2] = "a", t[3] = 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))

    print(foo(2))

    print(foo(0))

    print(foo(3))

    将函数调用用一对圆括号括起来也可以强制其只返回一个结果:

    print((foo0())) --> nil

    print((foo1())) --> a

    print((foo2())) --> a

    应该意识到,return 语句后面的内容是不需要加括号的,如果加了括号会导致程序出现额外的行为。因此,无论f究竟返回了几个值,形如return (f(x))的语句只返回一个值。有时这可能是我们所希望出现的情况,但有时又可能不是。

    6.2 可变长参数函数

    Lua 语言中的函数可以是可变长参数函数,即可以支持数量可变的参数。例如,我们已经使用一个、两个或更多个参数调用过函数 print。虽然函数 print 是在 C 语言中定义的,但也可以在 Lua 语言中定义可变长参数函数。

    下面是一个简单的示例,该函数返回所有参数的总和:

    function add(...)

    local s = 0

    for _, v in ipairs{...} do

    s = s + v

    end

    return s

    end

    print(add(3, 4, 10, 25, 12)) --> 54

    参数列表中的三个点...表示该函数的参数是可变长的。当这个函数被调用时,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 do

    if arg[i] == nil then return false end

    end

    return true

    end

    print(nonils(2, 3, nil))

    print(nonils(2, 3))

    print(nonils())

    print(nonils(nil))

    另一种遍历函数的可变长参数的方法是使用函数 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 = 0

    for i = 1, select("#", ...) do

    s = s + select(i, ...)

    end

    return 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}) --> a = 10, b = 20, 30被丢弃

    顾名思义,函数table.unpack()与函数table.pack()的功能相反。pack 会把参数列表转换成 Lua 语言中一个真实的列表,而 unpack 则把 Lua 语言中真实的列表转换成一组返回值,进而可以作为一个函数的参数被使用。

    unpack 函数的重要用途之一体现在泛型调用机制中。泛型调用机制允许我们动态地调用具有任意参数的任意函数。例如,在 ISO C 中,我们无法编写泛型调用的代码,只能声明可变长参数的函数或者使用函数指针来调用不同的函数。但是,我们仍然不能调用具有可变数量参数的函数,因为 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)))

    通常,函数table.unpack()使用长度操作符获取返回值地个数,因而该函数只能用于序列。不过,如果有需要,也可以显式地限制返回元素的范围:

    print(table.unpack({"Sun", "Mon", "Tue", "Wed"}, 2, 3)) --> "Mon" "Tue"

    虽然预定义的函数 unpack 是用 C 语言编写的,但是也可以利用递归在 Lua 语言中实现:

    function unpack(t, i, n)

    i = i or 1

    n = n or #t

    if i <= n then

    return t[i], unpack(t, i + 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 语言可以正确地尾递归,虽然尾递归调用消除的概念并没有直接涉及递归,参见练习 6.6.

    尾调用是被当作函数调用使用的跳转。当一个函数的最后一个动作是调用另一个函数而没有再进行其他工作时,就形成了尾调用。例如,下面代码中对函数 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)

    return (g(x))

    在 Lua 语言中,只有形如return func(arg)的调用才是尾调用。不过,由于 Lua 语言会在调用前对 func 及其参数求值,所以 func 及其参数都可以是复杂的表达式。例如,下面的例子就是尾调用:

    return x[i].foo(x[j] + a * b, i + j)

    6.5 练习

    练习 6.1:请编写一个函数,该函数的参数为一个数组,打印出该数组的所有元素。

    function PrintArr(arr)

    for _,v in pairs(arr) do

    print(v)

    end

    end

    练习 6.2:请编写一个函数,该函数的参数为可变数量的一组值,返回值为除第一个元素之外的其他所有值。

    function PrintArr2(...)

    return table.unpack({...}, 2, select("#", ...))

    end

    print(PrintArr2(1,2,3,4,5))

    练习 6.3:请编写一个函数,该函数的参数为可变数量的一组值,返回值为除了最有一个元素之外的所有值。

    function PrintArr3(...)

    return table.unpack({...}, 1, select("#", ...) - 1)

    end

    print(PrintArr3(1,2,3,4,5,6))

    练习 6.4:请编写一个函数,该函数用于打乱一个指定的数组,请保证所有的排列都是等概率的。

    ---打乱输入进来的数组

    ---@return table

    ---@param arr table

    function Shuffle(arr)

    local t = {}

    math.randomseed(os.time())

    for i = #arr, 1, -1 do

    table.insert(t,table.remove(arr, math.random(i)))

    end

    return t

    end

    print(table.unpack(Shuffle({1,2,3,4,5})))

    练习 6.5:请编写一个函数,其参数为一个数组,返回值为数组中元素的所有组合。提示:可以使用组合的递推公式 C(n, m) = C(n - 1, m - 1) + C(n - 1, m)。要计算从 n 个元素中选出 m 个组成的组合 C(n, m),可以先将第一个元素加到结果集中,然后计算所有的其他元素的C(n - 1, m - 1);然后,从结果中删掉第一个元素,再计算其他所有剩余元素的 C(n - 1, m)。当 n 小于 m 时,组合不存在;当 m 为 0 时,只有一种组合(一个元素也没有)。

    这题比较难 以后再写

    练习 6.6:有时,具有正确尾调用的语句被称为 正确的尾递归,争论在于这种正确性只与递归调用有关(如果没有递归调用,那么一个程序的最大调用深度是静态固定的)。

    请证明上述争论的观点像 Lua 语言一样的动态语言中不成立:不使用递归,编写一个能够实现支持无限调用链的程序。

    想要实现无限调用链,就要在完成函数功能以后再返回自身,即是像 C++ 运算符重载那样,可以无限地使用 << 来对 cout 进行输出

    ---可以链式打印

    ---@return function

    ---@param n number

    function MyPrint(n)

    print(n)

    return MyPrint

    end

    MyPrint(1)(2)(3)(4)

    展开全文
  • Oracle日期函数:MONTHS_BETWEEN:返回两个日期之间月份的差值MONTHS_BETWEEN('01-EP-95','11-JAN-94')===>19.6774194ADD_MONTHS:在日期上加上份数.ADD_MONTHS('11-JAN-94',6)===>'11-JUL-94'NEXT_DAY:指定日期...
  • Vlookup实现多条件匹配

    千次阅读 2021-04-08 10:35:42
    只要在目标区域的首列添加一个辅助列,目的就是将多条件转化为一个单条件,这个时候我们就可以用Vlookup进行匹配了,请看下面的示例: 1、在A列前插入一空列,输入公式=B2&C2 2、在H2输入函数公式,用VLOOKUP...
  • mysql 聚合函数

    2021-01-19 08:10:29
    GROUP BY(聚合)函数本章论述了用于一组数值操作的 group (集合)函数。除非另作说明, group 函数会忽略 NULL 值。假如你在一个不包含 GROUP BY子句的语句中使用一个 group函数 ,它...若找不到匹配的行,则AVG()返回...
  • swift 函数返回值

    2020-12-21 06:21:39
    函数的定义及调用func开头作为前缀,->返回的类型add输出结果是11函数参数也可以有多个参数,写在括号里用逗号隔开。func introduce(name: String,age: Int) -> String{return "\(name),I'm \(age) year old ...
  • 在MySQL中,REGEXP_LIKE()函数用于确定字符串是否匹配正则表达式。如果字符串与提供的正则表达式匹配函数返回1;如果不匹配,返回0。语法:REGEXP_LIKE(expr, pat[, match_type])其中expr是输入字符串,pat是测试...
  • 一、模糊匹配还是部分匹配通过两个示例来说明部分匹配和模糊匹配是什么意思。示例1.按照简称匹配全称所对应的业务人员姓名,可以使用公式=VLOOKUP("*"&D2&"*",A:B,2,0)完成,如图所示。在第一参数D2的两边...
  • Excel表VLOOKUP多个条件匹配数据

    千次阅读 2021-07-16 10:01:08
    可以使用VLOOKUP和IF{1,0}函数组合,具体公式为: =VLOOKUP(条件1&条件2,if({1,0},条件1范围&条件2范围,结果范围),2,0) 样例: 有三点需要注意: 1)条件1&条件2,选择单值;否则匹配结果只是第一行...
  • MySQL中的常见函数

    2021-02-08 10:07:49
    字符函数length(str):用于获取参数值得字节个数,其中汉字算3位。concat(列表):列表所在列的内容进行拼接。upper、lower:将字符进行大小写转换。substr、substring:获取子字符串,指定起始索引(从1开始)和长度。...
  • excel无序查询 使用LOOKUP函数实现无序查询,在这个电脑办公的时代,要是不掌握点office办公软件相关的知识那你简直就没有晋升的机会了,excel无序查询这个问题,不知道是否也困扰着你,关于excel无序查询 使用...
  • excel-LOOKUP函数多条件查找

    千次阅读 2021-01-27 17:15:46
    注意: Lookup() 多条件查找时无需排序,正常LOOKUP函数要求“查找区域”中的值必须按升序排列,因为是二分法原理 举例: LOOKUP(1,0/(($A2:2:2:A9=E2)∗(9=E2)*(9=E2)∗(B2:2:2:B9=F2)),9=F2)),9=F2)),C2:2:2:C$9)...
  • MySQL学习笔记—自定义函数注释语法:MySQL服务器支持3种注释风格:从‘#’字符从行尾。从‘– ’序列到行尾。请注意‘– ’(双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如空格、tab、换行符等等)。该...
  • 一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait(特征)定义的方式与类类似,但它使用的关键字是trait。 5.2 具体写法 5.2.1.trait中带属性带方法实现 注意: 继承的多个trait中如果有...
  • SQL中的替换函数replace总结

    千次阅读 2021-08-20 17:55:03
    SQL中的替换函数replace总结 sql中的替换分为三种:1、查询替换;2、更新替换;3新增替换。接下来我会举几个例子! 1、replace语法: 语法: REPLACE ( string_expression , string_pattern , string_replacement )...
  • C++ 多重继承

    千次阅读 热门讨论 2021-05-13 04:17:10
    C++ 多重继承. 多重继承是什么, 多重继承的优缺点以及注意事项.
  • c++开根号函数?

    千次阅读 2021-05-23 05:39:00
    例如://参考代码如下://做到前后标签匹配#include"iostream"#include"stdlib.h"#include"math.h"usingnamespacestd;intmain(){doublenum,s,p,n=3;cin>>num;//输入nums=sqrt(num);//求根号nump...
  • 函数指针、二重指针 1.指针数组与数组指针 1.1、字面意思来理解指针数组与数组指针 (1)指针数组的实质是一个数组,这个数组中存储的内容全部是指针变量。 (2)数组指针的实质是一个指针,这个指针指向的是一个数组。 ...
  • 目录前言:距离上一篇博客已经有一个多月了(劳逸结合emmmmm),这里对于mysql常见的函数做一个归纳,方便查询以及系统化的学习,建议多看多用->(调用方式均为select 函数名(实参列表) 【from 表】)。一、单行函数...
  • 以图搜图-自动生成图模式匹配Cypher以图搜图-自动生成图模式匹配Cypher一、函数使用方式二、autoCypher返回的格式三、过滤器3.1 属性过滤器3.2 Elasticsearch过滤器四、使用场景五、依赖六、根据`auto-cypher分析的...
  • 实验四ZEMAX评价函数光学设计及CAD实验手册ZEMAX 入门指南向阳 牟达 编写实验一 ZEMAX用户界面简要说明及操作要点一、实验目的:了解光学设计软件ZEMAX的特点、ZEMAX的用户界面和ZEMAX的相关功能和操作要点。...
  • Python程序的结构Python的程序由包,模块(即一个Python文件)和函数组成。包是由一系列模块组成的集合。模块是处理某一类问题的函数和类的集合。包中必须至少含有一个__init__.py文件,该文件的内容可以为空。用于...
  • presto函数大全

    2021-11-03 17:01:49
    presto函数大全 参考官方文档 https://prestodb.io/docs/current/functions/conversion.html ****Functions and Operators****** 1. 逻辑操作 逻辑运算符 操作 描述 例子 AND 两个值都为true,则为true a AND...
  • mysql中regexp_like函数的用法

    千次阅读 2021-01-27 09:58:03
    mysql中regexp_like函数的用法发布时间:2020-05-06 15:12:47来源:亿速云阅读:316作者:三月下文主要给大家带来mysql中regexp_like函数的用法,希望...在MySQL中,REGEXP_LIKE()函数用于确定字符串是否匹配正则...
  • R语言︱缺失值处理之多重插补

    千次阅读 2020-12-30 07:49:18
    笔者寄语:缺失值是数据清洗过程中非常重要的问题(其他方法可见:R语言︱异常值检验、离群点分析、异常值处理),笔者在进行mice包的多重插补过程中遇到相当多的问题。大致的步骤简介如下:缺失数据集——MCMC估计...
  • oracle函数教程

    2021-04-30 09:53:27
    新版w3school学院编写了全新的oracle函数教程Oracle基础知识部分涵盖了Oracle数据库的基础知识。本系列教程的主要目标是帮助您构建强大的Oracle数据库基础。完成本系列后,您将能够编写复杂的SQL语句来查询数据和...
  • solidity函数相关总结

    2021-05-11 11:01:32
    function (<parameter types>) {private|internal|external|public} [pure|...函数重载是指函数命名相同,但需要满足以下两个条件: 函数传入参数的数量不同 函数传入参数的类型不同 若函数与多个参数均...
  • EXCEL 2016常用知识--Excel函数

    千次阅读 2021-11-17 19:56:46
    必备常用函数教学,包括逻辑函数、查找函数、文本函数、数学函数等… 1.Excel计算的两种方式 Excel计算的两种方式: 公式:一些运算符和数值组成的数学表达式 函数:是Excel内部设置好的运算模块 Excel中的公式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,739
精华内容 17,895
关键字:

多重匹配函数