- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 Rust 中尝试了函数指针魔术,最终得到了一个代码片段,我完全没有解释它为什么编译,甚至更多,为什么它运行。
fn foo() {
println!("This is really weird...");
}
fn caller<F>() where F: FnMut() {
let closure_ptr = 0 as *mut F;
let closure = unsafe { &mut *closure_ptr };
closure();
}
fn create<F>(_: F) where F: FnMut() {
caller::<F>();
}
fn main() {
create(foo);
create(|| println!("Okay..."));
let val = 42;
create(|| println!("This will seg fault: {}", val));
}
我无法解释为什么
foo
正在通过在
caller(...)
中转换空指针来调用到
F
类型的实例.我原以为只能通过相应的函数指针调用函数,但鉴于指针本身为空,显然情况并非如此。话虽如此,似乎我显然误解了 Rust 类型系统的一个重要部分。
最佳答案
这个程序实际上根本没有构造函数指针——它总是调用 foo
和这两个直接关闭。
每个 Rust 函数,无论是闭包还是 fn
item,具有唯一的匿名类型。这种类型实现了 Fn
/FnMut
/FnOnce
特征,视情况而定。 fn
的匿名类型item 的大小为零,就像没有捕获的闭包类型一样。
因此,表达式 create(foo)
实例化 create
的参数 F
与 foo
的类型 - 这不是函数指针类型 fn()
,但是一个匿名的、零大小的类型,仅用于 foo
.在错误消息中,rustc 调用此类型 fn() {foo}
,如您所见 this error message .
内create::<fn() {foo}>
(使用错误消息中的名称),表达式 caller::<F>()
将此类型转发到 caller
而不给它一个该类型的值。
最后,在 caller::<fn() {foo}>
表达式 closure()
脱糖至 FnMut::call_mut(closure)
.因为 closure
有类型 &mut F
哪里F
只是零尺寸类型 fn() {foo}
, 0
closure
的值本身根本就没有被使用过1,并且程序调用了foo
直接地。
同样的逻辑适用于闭包 || println!("Okay...")
, 喜欢 foo
有一个匿名的零大小类型,这次叫做 [closure@src/main.rs:2:14: 2:36]
.
第二个闭包就没有那么幸运了——它的类型不是零大小的,因为它必须包含对变量 val
的引用。 .这一次,FnMut::call_mut(closure)
实际上需要取消引用 closure
做它的工作。所以它崩溃了2。
1 像这样构造一个空引用在技术上是未定义的行为,因此编译器不对该程序的整体行为作出 promise 。但是,替换 0
与其他一些“地址”对齐 F
避免了零大小类型的问题,例如 fn() {foo}
,并给出 the same behavior !)
2 同样,构造一个空(或悬空)引用是实际承担责任的操作 - 之后,任何事情都会发生。段错误只是一种可能性 - rustc 的 future 版本,或者在稍微不同的程序上运行时的相同版本,可能会完全做其他事情!
关于rust - 为什么 Rust 允许通过空指针调用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63164973/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!