`
hqs7636
  • 浏览: 220349 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

函 数 2 (2.014)

阅读更多
7 嵌套函数

函数可以被嵌套在其它函数内部:

int bar(int a)
{
int foo(int b)
{
int abc() { return 1; }
return b + abc();
}
return foo(a);
}
void test()
{
int i = bar(3); // i 被赋值为 4
}

嵌套函数只在其名字 处在作用域中 时才能被访问。
void foo()
{
void A()
{
B(); // 错误,B() 被向前引用了
C(); // 错误,C 未定义
}
void B()
{
A(); // 正确,在作用域内
void C()
{
void D()
{
A(); // 正确
B(); // 正确
C(); // 正确
152
第 15 章 函数
D(); // 正确
}
}
}
A(); // 正确
B(); // 正确
C(); // 错误,C 未定义
}

和:
int bar(int a)
{
int foo(int b) { return b + 1; }
int abc(int b) { return foo(b); } // 正确
return foo(a);
}
void test()
{
int i = bar(3); // 正确
int j = bar.foo(3); // 错误,bar.foo 不可见
}


嵌套函数可以访问由词法上封闭函数所定义的变量和其它符号。这里的“访问”包含既可以
读,也可以写两种能力。

int bar(int a)
{ int c = 3;
int foo(int b)
{
b += c; // 4 被加到 b 上
c++; // bar.c 现在为 5
return b + c; // 返回 12
}
c = 4;
int i = foo(a); // i 被设置为 12
return i + c; // 返回 17
}
void test()
{
int i = bar(3); // i 被赋值为 17
}

这种访问能力能够跨越多重嵌套:
int bar(int a)
{ int c = 3;
int foo(int b)
{
int abc()
{
return c; // 访问 bar.c
}
return b + c + abc();
}
return foo(3);
}

静态嵌套函数不能访问外围函数的任何堆栈变量,但能访问静态变量。这种行为同静态成员
函数类似。

int bar(int a)
{ int c;
static int d;
static int foo(int b)
{
b = d; // 正确
b = c; // 错误,foo() 不能访问 bar() 的堆栈帧
return b + 1;
}
return foo(a);
}

函数可以嵌套在成员函数内:
struct Foo
{ int a;
int bar()
{ int c;
int foo()
{
return c + a;
}
return 0;
}
}

嵌套结构和嵌套类的成员函数不能访问外围函数的堆栈变量,但是能访问其他的符号:

void test()
{ int j;
static int s;

struct Foo
{ int a;
int bar()
{ int c = s; // 正确,s 是静态的
int d = j; // 错误,不能访问 test() 的堆栈帧
int foo()
{
int e = s; // 正确,s 是静态的
int f = j; // 错误,不能访问 test() 的堆栈帧
return c + a; // 正确,bar() 的堆栈帧是可访问的,
// 通过指向 Foo.bar() 的 this 指针
// 可以访问 Foo 的成员
}
return 0;
}
}
}

嵌套函数总是使用 D 函数链接类型。

同模块级的声明不同,函数作用域的声明会按照声明的顺序处理。这意味着连个嵌套函数不
能互相调用:

void test()
{
void foo() { bar(); } // 错误,bar 没有被定义
void bar() { foo(); } // 正确
}

解决的方法是使用委托:
void test()
{
void delegate() fp;
void foo() { fp(); }
void bar() { foo(); }
fp = &bar;
}

未来的方向 这个限制可能会被删除。


7.1 委托、函数指针和动态闭包
Delegates, Function Pointers, and Closures(2.014,不动态了?)


函数指针可以指向一个静态嵌套函数:

int function() fp;
void test()
{ static int a = 7;
static int foo() { return a + 3; }
fp = &foo;
}
void bar()
{
test();
int i = fp(); // i 被设置为 10
}

委托可以用非静态嵌套函数赋值:

int delegate() dg;
void test()
{ int a = 7;
int foo() { return a + 3; }
dg = &foo;
int i = dg(); // i 被设置为 10
}

但是,一旦声明堆栈变量的函数退出了,堆栈变量就不再有效;同样的,
指向堆栈变量的指针也不再有效:

int* bar()
{ int b;
test();
int i = dg(); // 错误,test.a 不再存在
return &b; // 错误,bar.b 在 bar() 退出后不再有效
}


上面这段被改成:2.014
The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure. Returning addresses of stack variables, however, is not a closure and is an error.

int* bar()
{   int b;
    test();
    int i = dg(); // ok, test.a is in a closure and still exists
    return &b; // error, bar.b not valid after bar() exits
}



非静态嵌套函数的委托包括两块数据:指向外围函数堆栈帧的指针(叫做 帧指针)和函数
的地址。与此类似,结构/类的非静态成员函数委托由 this 指针和成员函数的地址组成。这
两种形式的委托可以互相转换,实际上它们具有相同的类型:

struct Foo
{ int a = 7;
int bar() { return a; }
}
int foo(int delegate() dg)
{
return dg() + 1;
}
void test()
{
int x = 27;
int abc() { return x; }
Foo f;
int i;
i = foo(&abc); // i 被设置为 28
i = foo(&f.bar); // i 被设置为 8
}

环境和函数的结合被称作 动态闭包。

委托的 .ptr 特性会返回 帧指针 值,而类型为 void*。

委托的 .funcptr 属性会返回 帧指针 值,类型为函数类型。

未来的方向 函数指针和委托或能被合并成一种通用的语法并且彼此可以互相更改。


7.2 匿名函数和匿名委托

参看 函数字法。(参见 操作符与表达式 3 --> 基本表达式 21.10 函数字法)


8 main() 函数

对于控制台程序,main() 提供入口点。它会在所有的模块初始化,以及所有的单元测试都
被运行以后被调用。在它返回以后,所有的模块析构函数会得到运行。main() 必须使用下
列形式之一进行声明:
void main() { ... }
void main(char[][] args) { ... }
int main() { ... }
int main(char[][] args) { ... }


9 编译时 函数执行

有些函数的子集可以在编译时执行。这个在常量合拢(constant folding)需要包括递归
(recursion)和循环时很有用。为了在编译时可以被执行,此函数必须符号下面的标准
(criteria):

1. 函数形参都必须是:
• 整数文字
• 浮点文字
• 字符文字
• 字符串
• 数组文字,即所有成员都是这个列表的条目
• 关联数组文字,即所有成员都是这个列表的条目
• 结构文字,即所有成员都是这个列表的条目
• const 变量使用这个列表的一个成员进行初始化

2. 函数参数不能是参数可变型或者是 lazy 型
3. 函数不能被嵌套或同步(synchronized)
4. 函数不能是非静态(non-static)成员,即它不能有 this 指针

5. 在函数里的表达式不能:
• 抛出异常
• 使用指针、委托、非常量数组或者类
• 引用任何全局状态(state)或变量
• 引用任何局部变量
• 进行 new 或 delete 操作
• 调用任何在编译时不可执行的函数

6. 不允许下列语句类型:
• synchronized 语句
• throw 语句
• with 语句
• scope 语句
• try-catch-finally 语句
• 带标号的 break 和 continue 语句

7. 作为特殊情况,下列特性可以在编译时执行:
.dup
.length
.keys
.values

为了在编译时执行,函数必须出现在它必须那样执行的环境里,

比如:
• 静态变量的初始化
• 静态数组的维
• 用于模板值参(value parameter)的形式参数

template eval( A... )
{
const typeof(A[0]) eval = A[0];
}
int square(int i) { return i * i; }
void foo()
{
static j = square(3); // 编译时
writefln(j);
writefln(square(4)); // 运行时
writefln(eval!(square(5))); // 编译时
}

在编译时执行函数会比在运行时的执行花费更长的时间。如果函数进行无限循环状态,那么
它就会在编译时挂起(hang)(而不会在运行时挂起)。

在编译时执行的函数在下列场景下会给出跟运行时不同的结果:

• 浮点计算可能会以比运行时更高的精度进行
• 依赖于实现所定义的求值顺序
• 使用未初始化的变量

这些场景都跟不同优化设置影响会影响结果那样的场景一样。


9.1 字符串 混入和编译时的 函数执行

所有在编译时执行的函数都必须是在运行时可执行的。一个函数的编译时求值所完成的是跟
在运行时运行函数一样的。即表示函数的语义不能依赖于函数的编译时得到的值。

例如:
int foo(char[] s)
{
return mixin(s);
}
const int x = foo("1");
它就是非法的,因为不能为 foo() 生成运行时代码。函数模板用于实现此类事情会是种比较
合适的方法。



.........
分享到:
评论

相关推荐

    艺术ppt-素材 014.pptx

    ### 2. 广告设计资源的应用场景 #### 内容概述: 文件中提到了一系列广告设计资源,包括海报、易拉宝、展板等,这些资源可以用于不同的商业宣传活动。 #### 关键知识点: - **海报**:适用于各种宣传场合,如产品...

    VB编程资源大全(源码 其它3)

    o029_snow.zip 一个雪花飘落例子(3KB) 626,o028_zoomsys.zip 类似画图放大镜的东西(2KB) 627,o027_wiz2.zip 制作应用程序向导的例子(类似安装程序的界面)!(5KB) 628,o025_StopWatch.zip “跑表...

    HR常用表格3.pdf

    2. **应聘人员登记表(HR-002)**:求职者在申请职位时填写,包括个人信息、教育背景、工作经验、技能特长等,帮助HR初步了解候选人的基本情况。 3. **面试评估表(HR-003)**:面试官根据应聘者的面试表现进行评分...

    VB编程资源大全(源码 其它2)

    o029_snow.zip 一个雪花飘落例子(3KB) 626,o028_zoomsys.zip 类似画图放大镜的东西(2KB) 627,o027_wiz2.zip 制作应用程序向导的例子(类似安装程序的界面)!(5KB) 628,o025_StopWatch.zip “跑表...

    人力资源部HR常用表格模板.docx

    #### 2. 应聘人员登记表 (JQSW-HR-002) - **用途**:收集应聘者的个人信息及背景资料,作为初步筛选的依据。 - **主要内容**:包括个人基本信息(如姓名、性别、年龄等)、教育背景、工作经验、技能特长等。 - **...

    JDK 1.5的泛型實現(Generics in JDK 1.5)

    JDK 1.5的泛型實現(Generics in JDK 1.5) 1 侯捷觀點 JDK 1.5的泛型實現 .......................讓我們把帶有「參數化型別」...#014 this(10); #015 } #016 ... #017 } 圖 9a / JDK1.5的 java.util.ArrayList源碼 ...

    VB编程资源大全(源码 其它1)

    o029_snow.zip 一个雪花飘落例子(3KB) 626,o028_zoomsys.zip 类似画图放大镜的东西(2KB) 627,o027_wiz2.zip 制作应用程序向导的例子(类似安装程序的界面)!(5KB) 628,o025_StopWatch.zip “跑表...

    VB编程资源大全(源码 其它4)

    o029_snow.zip 一个雪花飘落例子(3KB) 626,o028_zoomsys.zip 类似画图放大镜的东西(2KB) 627,o027_wiz2.zip 制作应用程序向导的例子(类似安装程序的界面)!(5KB) 628,o025_StopWatch.zip “跑表...

    湖南省醴陵二中醴陵四中2017_2018学年高二数学下学期期中联考试题文20180511122

    2. **函数的性质**:函数的连续性和零点的概念,比如题目中的函数`f(x)`的零点问题,要求找到函数在给定区间内零点的个数,这涉及到函数的零点定理和介值定理。 3. **坐标变换**:曲线`y=sin2x`经过伸缩变换后的...

    新课标版2015_2016学年高一数学上学期第三次月考试题

    2. **幂函数**:题目提到了函数32)32()(mxmxf是幂函数。幂函数的形式为y = x^m,其中m是常数。根据题目,m = 3或m = 2,但题目要求m的值,所以m = 1是幂函数的唯一可能值。 3. **函数零点**:题目中求函数f(x...

    新型膦酸自组装薄膜(SAMs)应用于n型苝二酰亚胺(PDI)有机场效应晶体管

    文章提到的实验结果显示,在空气环境下,使用膦酸SAMs修饰的绝缘层,尤其是使用ODPA(可能是一种具体的膦酸衍生物)的SAMs,显著提高了基于PDI-i8C的OFETs的电子迁移率,达到了0.014 cm^2 V^-1 s^-1,相较于未修饰的...

Global site tag (gtag.js) - Google Analytics