Rust Chars
练习题
codewars
上有一道题:
This time no story, no theory.
The examples below show you how to write function
accum
:Examples:
accum("abcd") -> "A-Bb-Ccc-Dddd" accum("RqaEzty") -> "R-Qq-Aaa-Eeee-Zzzzz-Tttttt-Yyyyyyy" accum("cwAt") -> "C-Ww-Aaa-Tttt"
The parameter of accum is a string which includes only letters from
a..z
andA..Z
.
要求实现accum()
。
题目本身不难,大体思路是:对于入参,转变成字符列表,然后对每个字符进行repeat
m 次,m就等于该字符在字符串的index,(repeat
结果的首字母大写),最后使用-
将这些结果join
起来就完成了。
对于str
有个chars()
方法,文档说明:
pub fn chars(&self) -> Chars<'_>
例如:
let word = "goodbye";
let mut chars = word.chars();
assert_eq!(Some('g'), chars.next());
assert_eq!(Some('o'), chars.next());
assert_eq!(Some('o'), chars.next());
assert_eq!(Some('d'), chars.next());
assert_eq!(Some('b'), chars.next());
assert_eq!(Some('y'), chars.next());
assert_eq!(Some('e'), chars.next());
assert_eq!(None, chars.next());
返回的Chars
类型,是str
的在其chars
的迭代器。
接下来我们会对每个字符做map
操作,但是我们同时需要每个字符在字符串的index位置。这时候就要介绍一下enumerate()
方法。在迭代数据的时候,同时给出当前的索引值。
fn enumerate(self) -> Enumerate<Self>
例如:
let a = ['a', 'b', 'c'];
let mut iter = a.iter().enumerate();
assert_eq!(iter.next(), Some((0, &'a')));
assert_eq!(iter.next(), Some((1, &'b')));
如何重复某个字符m次?标准库里有个repeat()
方法:
let a= "a";
let b= std::iter::repeat(a).take(3).collect::<String>();
println!("result {}",b);
关于join()
方法,先看看其在slice
的定义:
pub fn join<Separator>(
&self,
sep: Separator
) -> <[T] as Join<Separator>>::Output
where
[T]: Join<Separator>,
将slice
T 转变成使用Separator
连接的Output
类型的值。
Join
是个trait
它的定义是
pub trait Join<Separator> {
type Output;
fn join(slice: &Self, sep: Separator) -> Self::Output;
}
其中定义了一个 Associated Type
Output
。Join trait
自带了几个实现:
//使用 &str join [S],这个最常用
impl<'_, S> Join<&'_ str> for [S]
where
S: Borrow<str>,
例如:
assert_eq!(["hello", "world"].join(" "), "hello world");
//使用 &T join [V]
impl<'_, T, V> Join<&'_ T> for [V]
where
T: Clone,
V: Borrow<[T]>,
例如:
//这里 T 与 V 是同一个type了
assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
//使用 &[T] join [V]
impl<'_, T, V> Join<&'_ [T]> for [V]
where
T: Clone,
V: Borrow<[T]>,
例如:
assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
讲完slice
再讲讲std::vev::Vec
的join()
方法。
嗯,就比较简单了,std::vev::Vec
凭借着 Methods from Deref<Target = [T]> Vec
直接就具备了slice
的能力。
好了吧上面的步骤组合起来的到解决方案:
fn accum(s:&str)->String {
s
.to_lowercase()
.chars()
.enumerate()
.map(|(i,e)| e.to_uppercase().to_string() +
&std::iter::repeat(e).take(i).collect::<String>() )
.collect::<Vec<_>>()
.join("-")
}
需要稍微解释的是我们将大写字母拼接上repeat()
了 m-1(刚好是i)次的字符。而不是repeat()
m次。
类图
于是趁着做这道题,就梳理一下str
,slice
,String
等等类型之间的关系。