在Rust编译时部分应用?

问题描述 投票:-2回答:2

我有一个带两个参数的函数(假设有两个字符串):

fn foo(x: String, y: String) -> String {
    x + y
}

我总是在编译时知道x,但我不知道y直到运行时。

如何在不为每个x复制粘贴函数的情况下编写此代码以获得最大效率?

rust compile-time
2个回答
4
投票

请注意,您的函数foo当前需要两个堆分配的字符串。这是另一个版本,它更加通用和高效(虽然我将在下面描述YMMV):

fn foo<T>(x: T, y: &str) -> String
where
    T: Into<String>,
{
    x.into() + y
}

assert_eq!(foo("mobile ", "phones"), "mobile phones");

连接几乎总是需要在某处进行内存分配,但是这个可以使用堆分配的字符串以及任意字符串片。如果x的容量足够大,它也可以避免重新分配,尽管考虑到x是从编译时已知的字符串中获得的,因此不太可能出现这种情况。 String::insert_str将允许我们恢复类型参数的位置,但是在字符串前面的插入具有O(n)成本。知道字符串连接的第一个操作数先验对于编译器来说在它可以采用的优化方面并不是非常有益。


让我们假设我们仍然希望在编译时执行部分函数。这似乎是const generics会发光的另一个用例。有了这个功能,人们确实可以在&'static str上使用类似尚未实现的语法来对这个函数进行单一化:

fn foo<const X: &'static str>(y: &str) -> String {
    x.to_string() + y
}

唉,const仿制药目前正在开发中,尚未做好准备。虽然不太符合人体工程学,但我们可以使用基于规则的宏复制为每个字符串文字实例化一个函数的效果:

macro_rules! define_foo {
    ($fname: ident, $x: literal) => {
        fn $fname (y: &str) -> String {
            $x.to_string() + y
        }
    }
}

使用:

define_foo!(bar, "Conan ");

assert_eq!(bar("Osíris"), "Conan Osíris");    

也可以看看:


1
投票

我能够在夜间使用const函数返回闭包:

#![feature(const_fn)]

fn foo(x: String, y: String) -> String {
    x + &y
}

const fn foo_applied(x: String) -> impl Fn(String) -> String {
    move |y| foo(x.clone(), y)
}

fn main() {
    let foo_1 = foo_applied("1 ".into());
    println!("{}", foo_1("2".into()));
    let foo_2 = foo_applied("2 ".into());
    println!("{}", foo_2("1".into()));
}

Playground

© www.soinside.com 2019 - 2024. All rights reserved.