GVKun编程网logo

Lua的function、closure和upvalue(lua function)

18

对于想了解Lua的function、closure和upvalue的读者,本文将提供新的信息,我们将详细介绍luafunction,并且为您提供关于angular-cli项目报Errorencount

对于想了解Lua的function、closure和upvalue的读者,本文将提供新的信息,我们将详细介绍lua function,并且为您提供关于angular-cli 项目报 Error encountered resolving symbol values statically. Function calls are not suppor...、antd 踩坑:value.locale is not a function、Cocos2d-x结构学习(十二)CCMoveBy、CCActionInterval、CCFiniteTimeAction、CCCallFunc、CC_SAFE_RETAIN、CCActionInst、FP - Pure function vs. Closure的有价值信息。

本文目录一览:

Lua的function、closure和upvalue(lua function)

Lua的function、closure和upvalue(lua function)

Lua 中的函数是一阶类型值(first-class value),定义函数就象创建普通类型值一样(只不过函数类型值的数据主要是一条条指令而已),所以在函数体中仍然可以定义函数。假设函数f2定义在函数f1中,那么就称f2为f1的内嵌(inner)函数,f1为f2的外包(enclosing)函数,外包和内嵌都具有传递性,即f2的内嵌必然是f1 的内嵌,而f1的外包也一定是f2的外包。内嵌函数可以访问外包函数已经创建的所有局部变量,这种特性便是所谓的词法定界(lexical scoping),而这些局部变量则称为该内嵌函数的外部局部变量(external local variable)或者upvalue(这个词多少会让人产生误解,因为upvalue实际指的是变量而不是值)。试看如下代码:

function f1(n) -- 函数参数也是局部变量
  local function f2()
   print(n) -- 引用外包函数的局部变量 
  end 
  return f2
end
g1 = f1(1979)
g1() -- 打印出1979g2 = f1(500)g2() -- 打印出500
当执行完g1 = f1(1979)后,局部变量n的生命本该结束,但因为它已经成了内嵌函数f2(它又被赋给了变量g1)的upvalue,所以它仍然能以某种形式继续“存活”下来,从而令g1()打印出正确的值。
可为什么g2与g1的函数体一样(都是f1的内嵌函数f2的函数体),但打印值不同?这就涉及到一个相当重要的概念——闭包(closure)。事实上,Lua编译一个函数时,会为它生成一个原型(prototype),其中包含了函数体对应的虚拟机指令、函数用到的常量值(数,文本字符串等等)和一些调试信息。在运行时,每当Lua执行一个形如function...end 这样的表达式时,它就会创建一个新的数据对象,其中包含了相应函数原型的引用、环境(environment,用来查找全局变量的表)的引用以及一个由所有upvalue引用组成的数组,而这个数据对象就称为闭包。由此可见,函数是编译期概念,是静态的,而闭包是运行期概念,是动态的。g1和g2的值严格来说不是函数而是闭包,并且是两个不相同的闭包,而每个闭包可以保有自己的upvalue值,所以g1和g2打印出的结果当然就不一样了。虽然闭包和函数是本质不同的概念,但为了方便,且在不引起混淆的情况下,我们对它们不做区分。
使用upvalue很方便,但它们的语义也很微妙,需要引起注意。比如将f1函数改成:
function f1(n) 
  local function f2() 
     print(n) 
     end
   n = n + 10 
   return f2
g1 = f1(1979)g1() -- 打印出1989
内嵌函数定义在n = n + 10这条语句之前,可为什么g1()打印出的却是1989?upvalue实际是局部变量,而局部变量是保存在函数堆栈框架上(stack frame)的,所以只要upvalue还没有离开自己的作用域,它就一直生存在函数堆栈上。这种情况下,闭包将通过指向堆栈上的upvalue的引用来访问它们,一旦upvalue即将离开自己的作用域(这也意味着它马上要从堆栈中消失),闭包就会为它分配空间并保存当前的值,以后便可通过指向新分配空间的引用来访问该upvalue。当执行到f1(1979)的n = n + 10时,闭包已经创建了,但是n并没有离开作用域,所以闭包仍然引用堆栈上的n,当return f2完成时,n即将结束生命,此时闭包便将n(已经是1989了)复制到自己管理的空间中以便将来访问。弄清楚了内部的秘密后,运行结果就不难解释了。
upvalue还可以为闭包之间提供一种数据共享的机制。试看下例:
function Create(n) 
  local function foo1() 
    print(n) 
  end
  local function foo2() 
    n = n + 10 
  return foo1,foo2
f1,f2 = Create(1979)
f1() -- 打印1979 
f2() f1() -- 打印1989 
f2() f1() -- 打印1999 函数foo1和foo2,而foo1和foo2引用的upvalue是同一个,即Create的局部变量 n。前面已说过,执行完Create调用后,闭包会把堆栈上n的值复制出来,那么是否f1和f2就分别拥有一个n的拷贝呢?其实不然,当Lua发现两个闭包的upvalue指向的是当前堆栈上的相同变量时,会聪明地只生成一个拷贝,然后让这两个闭包共享该拷贝,这样任一个闭包对该upvalue进行修改都会被另一个探知。上述例子很清楚地说明了这点:每次调用f2都将upvalue的值增加了10,随后f1将更新后的值打印出来。upvalue的这种语义很有价值,它使得闭包之间可以不依赖全局变量进行通讯,从而使代码的可靠性大大提高。

angular-cli 项目报 Error encountered resolving symbol values statically. Function calls are not suppor...

angular-cli 项目报 Error encountered resolving symbol values statically. Function calls are not suppor...

安装同事打包的一个模块,报了这么个错,不过在其他地方使用是正常的。

Error encountered resolving symbol values statically. Function calls are not supported.

解决的办法

在 tsconfig.json 文件中添加

{
  ...
  "compilerOptions": {
    ..
    "skipLibCheck": true,
    "noStrictGenericChecks": false,
    "paths": {
      "@angular/*": ["../node_modules/@angular/*"],
     ...
    }
  },
  "exclude": [
    ...
  ]
}

 

antd 踩坑:value.locale is not a function

antd 踩坑:value.locale is not a function

这个问题来源于日期选择器 RangerPicker 的特殊情况。

<Col span={7} key={9}>
                                <FormItem label="投运时间" {...formItemLayout2}>
                                    {getFieldDecorator(''tysj'', {
                                        initialValue: [undefined, moment().endOf(''month'')],
                                        rules: [
                                            {
                                                required: false,
                                                message: ''投运时间!'',
                                            },
                                        ],
                                    })(<RangerPicker style={{ width:''100%''}} format="YYYY-MM-DD" allowClear={true} />)}
                                </FormItem>
                            </Col>

有时我们希望默认值一边有范围,一边没有范围。

比如 几月几号之前。

那么在表单赋值的时候,原先写的是:

initialValue: ['''', moment().endOf(''month'')],

但是这样会导致清除时报错:

value.locale is not a function

而只要改成:

initialValue: [undefined, moment().endOf(''month'')],

就可以了。

 

Cocos2d-x结构学习(十二)CCMoveBy、CCActionInterval、CCFiniteTimeAction、CCCallFunc、CC_SAFE_RETAIN、CCActionInst

Cocos2d-x结构学习(十二)CCMoveBy、CCActionInterval、CCFiniteTimeAction、CCCallFunc、CC_SAFE_RETAIN、CCActionInst

1、CCMoveBy:移动动作,继承自CCActionInterval

class CC_DLL CCMoveBy : public CCActionInterval
{
public:
    bool initWithDuration(float duration,const CCPoint& deltaPosition);   //初始化序列
    virtual CCObject* copyWithZone(CCZone* pZone);
    virtual void startWithTarget(CCNode *pTarget);               //开始目标
    virtual CCActionInterval* reverse(void);                    
    virtual void update(float time);                         //更新

public:
    static CCMoveBy* create(float duration,const CCPoint& deltaPosition);
protected:
    CCPoint m_positionDelta;
    CCPoint m_startPosition;
    CCPoint m_prevIoUsPosition;
};
2、CCActionInterval:动作间隔类,继承自CCFiniteTimeAction
class CC_DLL CCActionInterval : public CCFiniteTimeAction
{
public:
    inline float getElapsed(void) { return m_elapsed; }       //获取从动作开始到目前已逝去的秒

    bool initWithDuration(float d);                         //初始化动作

    virtual bool isDone(void);                        //判断动作是否运行完成

    virtual CCObject* copyWithZone(CCZone* pZone);
    virtual void step(float dt);
    virtual void startWithTarget(CCNode *pTarget);
    /** returns a reversed action */
    virtual CCActionInterval* reverse(void);

public:
    static CCActionInterval* create(float d);

public:
    void setAmplitudeRate(float amp);    //设置和获得扩展
    float getAmplitudeRate(void);
protected:
    float m_elapsed;
    bool   m_bFirstTick;
};
3、CCFiniteTimeAction:有限时间动作,继承自CCAction
class CC_DLL CCFiniteTimeAction : public CCAction
{
public:
    CCFiniteTimeAction()
        : m_fDuration(0)
    {}
    virtual ~CCFiniteTimeAction(){}

    inline float getDuration(void) { return m_fDuration; }                         //设置和获得持续时间
    inline void setDuration(float duration) { m_fDuration = duration; }

    virtual CCFiniteTimeAction* reverse(void);           //返回一个倒退序列
protected:
    float m_fDuration;
};
4、CCCallFunc:动作回调函数处理类,继承自CCActionInstant
class CC_DLL CCCallFunc : public CCActionInstant
{
public:
    CCCallFunc()
        : m_pSelectorTarget(NULL),m_nScriptHandler(0),m_pCallFunc(NULL)
    {
    }
    virtual ~CCCallFunc();

    static CCCallFunc * create(CCObject* pSelectorTarget,SEL_CallFunc selector);       //创建和初始化相关函数
    static CCCallFunc * create(int nHandler);
    virtual bool initWithTarget(CCObject* pSelectorTarget);
    virtual void execute();                      //执行

    virtual void update(float time);            //更新
  
    CCObject * copyWithZone(CCZone *pZone);
    inline CCObject* getTargetCallback()     //设置和获得回调对象
    {
        return m_pSelectorTarget;
    }
    inline void setTargetCallback(CCObject* pSel)
    {
        if (pSel != m_pSelectorTarget)
        {
            CC_SAFE_RETAIN(pSel);
            CC_SAFE_RELEASE(m_pSelectorTarget);
            m_pSelectorTarget = pSel; 
        }
    }

    inline int getScriptHandler() { return m_nScriptHandler; };            //得到脚本句柄
protected:
    CCObject*   m_pSelectorTarget;

    int m_nScriptHandler;

    union
    {
        SEL_CallFunc    m_pCallFunc;
        SEL_CallFuncN    m_pCallFuncN;
        SEL_CallFuncND    m_pCallFuncND;
        SEL_CallFuncO   m_pCallFuncO;
    };
};
5、CC_SAFE_RETAIN:这个宏有意思,搞个一次循环
#define CC_SAFE_RETAIN(p)            do { if(p) { (p)->retain(); } } while(0)
6、CCActionInstant:立即动作类,继承自CCFiniteTimeAction,比较简陋
class CC_DLL CCActionInstant : public CCFiniteTimeAction
{
public:
    CCActionInstant();
    virtual ~CCActionInstant(){}
    
    virtual CCObject* copyWithZone(CCZone *pZone);
    virtual bool isDone(void);
    virtual void step(float dt);
    virtual void update(float time);
    virtual CCFiniteTimeAction * reverse(void);
};

FP - Pure function vs. Closure

FP - Pure function vs. Closure

闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

定义:闭包名称源自于通过 “捕获” 自由变量的绑定,从而对函数字面量执行的 “关闭” 行动。不带自由变量的函数字面量,如:(x:Int) => x + 1,被称为封闭项(closed term),这里项(term)指的是一小部分源代码。因此依照这个函数字面量在运行时创建的函数值严格意义上来讲就不是闭包,因为 (x:Int) => x + 1 在编写的时候就已经封闭了。但任何带有自由变量的函数字面量,如:(x:Int) => x + more,都是开放项(open term)。因此,任何以 (x:Int) => x + more 为模板在运行期创建的函数值将必须捕获对自由变量 more 的绑定。因此得到的函数值将包含指向捕获的 more 变量的索引。又由于函数值是关闭这个开放项 (x:Int) => x + more 行动的最终产物,因此被称为闭包。 

1. 如 (x: Int) => x + 1 匿名函数,x 作为参数是已知的,整个表达式构成 封闭术语,函数在运行时就已经封闭的,根据引用透明的定义 (一个表达式可以被自身结果替代 [第一类值] 而不影响程式),而纯函数的定义是 —— 单例的引用透明表达式,所以不包含自由变量的函数就是纯函数。

2. 包含一个或多个自由变量,如 (x: Int) => x + more,其中 more 就是自由变量,more 只有在运行期才确定它的值,即惰性求值,由于函数值是关闭这个 [开放术语] (x: Int) => x + more 的行动的最终产物,得到的函数值将包含一个指向捕获的 more 变量的参考,因此被称为闭包。

我们今天的关于Lua的function、closure和upvaluelua function的分享就到这里,谢谢您的阅读,如果想了解更多关于angular-cli 项目报 Error encountered resolving symbol values statically. Function calls are not suppor...、antd 踩坑:value.locale is not a function、Cocos2d-x结构学习(十二)CCMoveBy、CCActionInterval、CCFiniteTimeAction、CCCallFunc、CC_SAFE_RETAIN、CCActionInst、FP - Pure function vs. Closure的相关信息,可以在本站进行搜索。

本文标签: