Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 如何编写一个同时接受所有和非所有字符串集合的函数?_String_Rust - Fatal编程技术网

String 如何编写一个同时接受所有和非所有字符串集合的函数?

String 如何编写一个同时接受所有和非所有字符串集合的函数?,string,rust,String,Rust,我在编写以字符串集合为参数的函数时遇到问题。我的函数如下所示: type StrList<'a> = Vec<&'a str>; fn my_func(list: &StrList) { for s in list { println!("{}", s); } } fn my_func<T: AsRef<str>>(list: &[T]) { for s in list {

我在编写以字符串集合为参数的函数时遇到问题。我的函数如下所示:

type StrList<'a> = Vec<&'a str>;

fn my_func(list: &StrList) {
    for s in list {
        println!("{}", s);
    }
}
fn my_func<T: AsRef<str>>(list: &[T]) {
    for s in list {
        println!("{}", s.as_ref());
    }
}
我的函数无法获取所拥有字符串的向量。相反,如果我将
StrList
类型更改为:

type StrList = Vec<String>;
但我觉得很奇怪
my_func
不应该关心字符串的所有权


我应该为
my_func
使用什么样的签名来支持所拥有字符串和字符串引用的向量?

虽然
string
&str
关系密切,但它们并不相同。下面是你的向量在内存中的样子:

v1-->[{0x7890,//指向“a”+7个未使用字节的指针
1}//“a”的长度
{0x7898,//指向“b”+7个未使用字节的指针
1}]//长度
v2-->[{0x1230//指向“a”+7个未使用字节的指针(另一个副本)
8/容量
1}//长度
{0x1238//指针。。。
8/容量
1}]//长度
这里的每一行都是相同的内存量(四个或八个字节,取决于指针大小)。你不能把其中一个的记忆当作另一个来对待。内存布局不匹配。项目大小不同,布局也不同。例如,如果
v1
存储从地址
X
开始的项目,
v2
存储从地址
Y
开始的项目,则
v1[1]
位于地址
X+8
v2[1]
位于地址
Y+12

您可以这样编写一个通用函数:

type StrList<'a> = Vec<&'a str>;

fn my_func(list: &StrList) {
    for s in list {
        println!("{}", s);
    }
}
fn my_func<T: AsRef<str>>(list: &[T]) {
    for s in list {
        println!("{}", s.as_ref());
    }
}
fn我的函数(列表:&[T]){
对于列表中的s{
println!(“{}”,s.as_ref());
}
}
然后编译器可以为
&[String]
&[&str]
以及其他类型生成适当的代码,如果它们实现了
AsRef

,我想指出您可以在这里添加的另一个泛型级别。你说:

字符串的集合

但是集合的类型比切片和向量更多!在您的示例中,您只关心对项目的一次一次的转发访问。这是
迭代器的完美示例。下面,我将您的函数更改为接受任何可以转换为迭代器的类型。然后可以传递更多类型的内容。我使用了一个
HashSet
作为示例,但是请注意,您也可以传入
v1
v2
,而不是
&v1
&v2
,使用它们

use std::collections::HashSet;

fn my_func<I>(list: I)
    where I: IntoIterator,
          I::Item: AsRef<str>,
{
    for s in list {
        println!("{}", s.as_ref());
    }
}

fn main() {
    let v1 = vec!["a", "b"];
    let v2 = vec!["a".to_owned(), "b".to_owned()];
    let v3 = {
        let mut set = HashSet::new();
        set.insert("a");
        set.insert("b");
        set.insert("a");
        set
    };
    let v4 = {
        let mut set = HashSet::new();
        set.insert("a".to_owned());
        set.insert("b".to_owned());
        set.insert("a".to_owned());
        set
    };

    my_func(&v1);
    my_func(v1);
    my_func(&v2);
    my_func(v2);
    my_func(&v3);
    my_func(v3);
    my_func(&v4);
    my_func(v4);
}
使用std::collections::HashSet;
fn my_func(列表:I)
其中I:into迭代器,
I::项目:AsRef,
{
对于列表中的s{
println!(“{}”,s.as_ref());
}
}
fn main(){
设v1=vec![“a”,“b”];
设v2=vec![“a”。to_owned(),“b”。to_owned();
设v3={
让mut set=HashSet::new();
集合。插入(“a”);
集合。插入(“b”);
集合。插入(“a”);
设置
};
设v4={
让mut set=HashSet::new();
set.insert(“a.to_owned());
set.insert(“b.”to_owned());
set.insert(“a.to_owned());
设置
};
my_func(&v1);
my_func(v1);
我的职能(&v2);
my_func(v2);
my_func(&v3);
my_func(v3);
我的职能(&v4);
my_func(v4);
}

它实际上是有效的。你能更好地解释一下为什么
&[T]
有效吗?
AsRef
很清楚。@brt您知道切片
&[T]
,只想知道为什么函数接受
&[T]
,但
main
传入
&Vec
,对吗?答案是。由于
&Vec
和[T]
的通用性要小得多(您可以从许多非向量的源中获得后者),因此最好编写接受
和[T]
的函数,而不是
&Vec
。对于人体工程学,
foo(&vec)
会自动从向量构建切片。这实际上更好@delnan实际上回答了我的问题,但是这个版本更通用。