在 Rust 中,是否可以从一个函数 return 一个静态函数?
In Rust, is it possible to return a static function from a function?
假设我在 Rust 中有以下类型:
type UnOp = fn(u64) -> u64;
该类型允许我创建不同的一元操作:
const add1 : UnOp = |x| x + 1;
const mul2 : UnOp = |x| x * 2;
现在,假设我需要 add2
、add3
、add4
(...),用于不同的数字,在我的代码的不同位置。编写所有定义会很麻烦,因此,我编写了一个通用的 adder
函数:
fn adder(add : u64) -> UnOp {
|x| x + add
}
这将允许我为任何数字写 add(2)
、add(3)
等:
// Prints 2 + 40
println!("result is: {}", adder(2)(40))
问题是:adder
实际上不是有效的 Rust 代码,因为 |x| ...
是一个闭包,而不是静态函数。为了让 adder
按我的意愿工作,我需要将 UnOp
修改为闭包:
type UnOp = Box<dyn Fn(u64) -> u64>;
fn adder(add : u64) -> UnOp {
Box::new(move |x| x + add)
}
问题是:如果我知道 adder(N)
的每个用法都应用于静态值怎么办?
在那种情况下,创建动态闭包在计算方面会很浪费。不仅如此,Box<dyn ...>
使代码大大复杂化,甚至可能需要生命周期注解。我的问题是:
是否可以在不修改 UnOp
的原始定义的情况下创建 adder
?也就是说,让 UnOp
成为静态函数,而不是闭包?
从逻辑上讲,没有理由不可能,只要 adder
的参数是静态的,Rust 就应该能够在编译时扩展它,以生成每个特定的实例。
编辑:其他详细信息
@Netwave 的回答提出的一个很好的解决方案是使用通用常量,它针对我给出的具体示例解决了这个问题。遗憾的是,如果 UnOp
是多态的,或者如果常量参数本身是一个函数,它就不起作用:
type UnOp<A> = fn(A) -> A;
pub fn adder<const ADD: u64>() -> UnOp<u64> {
|x| ADD + x
}
pub fn apply<A, const op : UnOp<A>, const x : A>() -> A {
return op(x);
}
这引发了 2 个错误:
- the type of const parameters must not depend on other generic parameters
- using function pointers as const generic parameters is forbidden
您可以使用 const Generics
:
type UnOp = fn(u64) -> u64;
const fn adder<const ADD: u64>(x: u64) -> u64 {
ADD + x
}
fn main() {
let add_1: UnOp = adder::<1>;
println!("{}", add_1(1));
}
Is it possible to create adder, without modifying the original definition of UnOp? That is, letting UnOp be a static function, NOT a closure?
既然你不解释为什么我会忽略这个要求。因为我认为你限制了你的选择。
您可能更喜欢巧妙地使用泛型和特征:
trait UnOp {
fn call(&self, _: u64) -> u64;
}
impl<F> UnOp for F
where
F: Fn(u64) -> u64,
{
fn call(&self, x: u64) -> u64 {
self(x)
}
}
fn adder(add: u64) -> impl UnOp {
move |x| x + add
}
假设我在 Rust 中有以下类型:
type UnOp = fn(u64) -> u64;
该类型允许我创建不同的一元操作:
const add1 : UnOp = |x| x + 1;
const mul2 : UnOp = |x| x * 2;
现在,假设我需要 add2
、add3
、add4
(...),用于不同的数字,在我的代码的不同位置。编写所有定义会很麻烦,因此,我编写了一个通用的 adder
函数:
fn adder(add : u64) -> UnOp {
|x| x + add
}
这将允许我为任何数字写 add(2)
、add(3)
等:
// Prints 2 + 40
println!("result is: {}", adder(2)(40))
问题是:adder
实际上不是有效的 Rust 代码,因为 |x| ...
是一个闭包,而不是静态函数。为了让 adder
按我的意愿工作,我需要将 UnOp
修改为闭包:
type UnOp = Box<dyn Fn(u64) -> u64>;
fn adder(add : u64) -> UnOp {
Box::new(move |x| x + add)
}
问题是:如果我知道 adder(N)
的每个用法都应用于静态值怎么办?
在那种情况下,创建动态闭包在计算方面会很浪费。不仅如此,Box<dyn ...>
使代码大大复杂化,甚至可能需要生命周期注解。我的问题是:
是否可以在不修改 UnOp
的原始定义的情况下创建 adder
?也就是说,让 UnOp
成为静态函数,而不是闭包?
从逻辑上讲,没有理由不可能,只要 adder
的参数是静态的,Rust 就应该能够在编译时扩展它,以生成每个特定的实例。
编辑:其他详细信息
@Netwave 的回答提出的一个很好的解决方案是使用通用常量,它针对我给出的具体示例解决了这个问题。遗憾的是,如果 UnOp
是多态的,或者如果常量参数本身是一个函数,它就不起作用:
type UnOp<A> = fn(A) -> A;
pub fn adder<const ADD: u64>() -> UnOp<u64> {
|x| ADD + x
}
pub fn apply<A, const op : UnOp<A>, const x : A>() -> A {
return op(x);
}
这引发了 2 个错误:
- the type of const parameters must not depend on other generic parameters
- using function pointers as const generic parameters is forbidden
您可以使用 const Generics
:
type UnOp = fn(u64) -> u64;
const fn adder<const ADD: u64>(x: u64) -> u64 {
ADD + x
}
fn main() {
let add_1: UnOp = adder::<1>;
println!("{}", add_1(1));
}
Is it possible to create adder, without modifying the original definition of UnOp? That is, letting UnOp be a static function, NOT a closure?
既然你不解释为什么我会忽略这个要求。因为我认为你限制了你的选择。
您可能更喜欢巧妙地使用泛型和特征:
trait UnOp {
fn call(&self, _: u64) -> u64;
}
impl<F> UnOp for F
where
F: Fn(u64) -> u64,
{
fn call(&self, x: u64) -> u64 {
self(x)
}
}
fn adder(add: u64) -> impl UnOp {
move |x| x + add
}