问题描述
我在做 2018年代码出现(第2天,第1部分) Rust中的解决方案.
I came across this while doing the 2018 Advent of Code (Day 2, Part 1) solution in Rust.
要解决的问题:
取具有完全相同的两个字母的字符串的计数,乘以具有完全相同的三个字母的字符串的计数.
Take the count of strings that have exactly two of the same letter, multiplied by the count of strings that have exactly three of the same letter.
输入
abcdega
hihklmh
abqasbb
aaaabcd
- 第一个字符串
abcdega
的a
重复了两次. - 第二个字符串
hihklmh
已将h
重复了三遍. - 第三个字符串
abqasbb
重复了两次a
,重复了三次b
,因此两者都算在内. - 第四个字符串
aaaabcd
包含一个重复4
次的字母(不是2
或3
),因此不算数. - The first string
abcdega
hasa
repeated twice. - The second string
hihklmh
hash
repeated three times. - The third string
abqasbb
hasa
repeated twice, andb
repeated three times, so it counts for both. - The fourth string
aaaabcd
contains a letter repeated4
times (not2
, or3
) so it does not count.
所以结果应该是:
2
包含双字母(第一个和第三个)的字符串乘以 2
包含三字母(第二和第三个)的字符串 = 4 代码>
2
strings that contained a double letter (first and third) multiplied by 2
strings that contained a triple letter (second and third) = 4
问题:
const PUZZLE_INPUT: &str =
"
abcdega
hihklmh
abqasbb
aaaabcd
";
fn letter_counts(id: &str) -> [u8;26] {
id.chars().map(|c| c as u8).fold([0;26], |mut counts, c| {
counts[usize::from(c - b'a')] += 1;
counts
})
}
fn has_repeated_letter(n: u8, letter_counts: &[u8;26]) -> bool {
letter_counts.iter().any(|&count| count == n)
}
fn main() {
let ids_iter = PUZZLE_INPUT.lines().map(letter_counts);
let num_ids_with_double = ids_iter.clone().filter(|id| has_repeated_letter(2, id)).count();
let num_ids_with_triple = ids_iter.filter(|id| has_repeated_letter(3, id)).count();
println!("{}", num_ids_with_double * num_ids_with_triple);
}
考虑第 21
行.函数 letter_counts
仅接受一个参数,因此我可以在与预期参数类型匹配的元素上使用语法: .map(letter_counts)
.这对我来说真的很好!我喜欢不必创建闭包: .map(| id | letter_counts(id))
.我发现两者都是可读的,但是没有封闭的前一个版本对我来说干净得多.
Consider line 21
. The function letter_counts
takes only one argument, so I can use the syntax: .map(letter_counts)
on elements that match the type of the expected argument. This is really nice to me! I love that I don't have to create a closure: .map(|id| letter_counts(id))
. I find both to be readable, but the former version without the closure is much cleaner to me.
现在考虑第 22
和 23
行.在这里,我必须使用语法: .filter(| id | has_repeated_letter(3,id))
,因为 has_repeated_letter
函数采用两个参数.我真的很想做 .filter(has_repeated_letter(3))
.
Now consider lines 22
and 23
. Here, I have to use the syntax: .filter(|id| has_repeated_letter(3, id))
because the has_repeated_letter
function takes two arguments. I would really like to do .filter(has_repeated_letter(3))
instead.
当然,我可以使函数取一个元组,映射到一个元组并仅使用一个参数……但这似乎是一个糟糕的解决方案.我宁愿只是创建闭包.
Sure, I could make the function take a tuple instead, map to a tuple and consume only a single argument... but that seems like a terrible solution. I'd rather just create the closure.
Rust允许您忽略 only 参数.如果编译器具有所有其他 n-1
参数,而为什么 last 参数却包含 n
个参数.
Leaving out the only argument is something that Rust lets you do. Why would it be any harder for the compiler to let you leave out the last argument, provided that it has all of the other n-1
arguments for a function that takes n
arguments.
我觉得这样可以使语法更加整洁,并且与Rust所喜欢的惯用功能样式更加匹配.
I feel like this would make the syntax a lot cleaner, and it would fit in a lot better with the idiomatic functional style that Rust prefers.
我当然不是编译器专家,但是实现此行为似乎很简单.如果我的想法不正确,那么我想知道更多关于为什么的想法.
I am certainly no expert in compilers, but implementing this behavior seems like it would be straightforward. If my thinking is incorrect, I would love to know more about why that is so.
推荐答案
不,您不能将带有多个参数的函数作为隐式闭包传递.
No, you cannot pass a function with multiple arguments as an implicit closure.
在某些情况下,您可以选择使用咖喱来减少 arity的功能.例如,在这里,我们将 add
函数从2个参数减少为一个:
In certain cases, you can choose to use currying to reduce the arity of a function. For example, here we reduce the add
function from 2 arguments to one:
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn curry<A1, A2, R>(f: impl FnOnce(A1, A2) -> R, a1: A1) -> impl FnOnce(A2) -> R {
move |a2| f(a1, a2)
}
fn main() {
let a = Some(1);
a.map(curry(add, 2));
}
但是,我同意这不是好处的评论:
However, I agree with the comments that this isn't a benefit:
-
输入的内容也不少:
It's not any less typing:
a.map(curry(add, 2));
a.map(|v| add(v, 2));
curry 函数非常受限制:它选择使用 FnOnce
,但是使用 Fn
和 FnMut
也有用例.它仅适用于具有两个参数的函数.
The curry
function is extremely limited: it chooses to use FnOnce
, but Fn
and FnMut
also have use cases. It only applies to a function with two arguments.
但是,我在其他项目中使用了这种高阶函数技巧,其中添加的代码量更大.
However, I have used this higher-order function trick in other projects, where the amount of code that is added is much greater.
这篇关于如何在不创建闭包的情况下调用多参数函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!