本人刚接触Rust两三天,想通过做题来快速熟悉Rust,在做LeetCode2.两数相加时,参考Rustgym写出了可以通过的代码,但还有一些疑问,先看全部的代码,其中的注释为个人理解,有错误还望指教:
/*
* @lc app=leetcode.cn id=2 lang=rust
*
* [2] 两数相加
*/
// @lc code=start
// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Clone, Debug)]
// pub struct ListNode {
// pub val: i32,
// pub next: Option<Box<ListNode>>
//}
// impl ListNode {
// #[inline]
// fn new(val: i32) -> Self {
// ListNode {
// next: None,
// val
// }
// }
// }
//定义一个别名
pub type ListLink = Option<Box<ListNode>>;
impl Solution {
pub fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
//sum为最后返回的答案
let mut sum: ListLink = None;
//p1为l1的借用
let mut p1: &ListLink = &l1;
//p2为l2的借用
let mut p2: &ListLink = &l2;
//p3为sum的可变借用
let mut p3: &mut ListLink = &mut sum;
//carry为进位
let mut carry = 0;
while p1.is_some() || p2.is_some() || carry != 0 {
//val定义为当前位置的结果,初始化为carry
let mut val = carry;
//as_ref()将&Option<T>变为Option<&T>
//n1和n2的类型为&T,这里有些不理解
if let Some(n1) = p1.as_ref() {
val += n1.val;
p1 = &n1.next;
}
if let Some(n2) = p2.as_ref() {
val += n2.val;
p2 = &n2.next;
}
//更新carry的值
carry = val / 10;
//解引用p3
*p3 = Some(Box::new(ListNode::new(val % 10)));
//更新p3,更新后实际上为None
p3 = &mut p3.as_mut().unwrap().next;
}
sum
}
}
// @lc code=end
其中有一部分不是很理解:
//as_ref()将&Option<T>变为Option<&T>
//n1和n2的类型为&T,这里有些不理解
if let Some(n1) = p1.as_ref() {
val += n1.val;
p1 = &n1.next;
}
if let Some(n2) = p2.as_ref() {
val += n2.val;
p2 = &n2.next;
}
这里的模式匹配是否推断n1
和n2
为&T
,T
在这里为Box<ListNode>
,为何之后的代码的行为可以像ListNode
一样,这里有些不懂,希望大神帮小白解答一下。
1
共 4 条评论, 1 页
评论区
写评论这样吗,还真没注意到,竟然不是实现的Asref trait。是因为其作用跟Asref trait取引用的原意不一样才选择作为成员函数的?
--
👇
Bai-Jinlin: 不过有一说一Option的as_ref不是Option实现了AsRef trait,而是那个就是一个Option的普通方法,Pin里的as_ref也是一个意思。
--
👇
Orca-bit: 十分感谢
👇
Aya0wind: 如果你是问as_ref为什么是把&Option变成Option<&T>,这个其实就是Option实现的的Asref trait干的事,没啥原因,他就是这么做的,就是一个转换,让你能方便的取到Option内部T的引用。 然后就是你问的Box为什么可以像T那样使用,因为Box实现了一个trait叫Deref,Rust有一个特性叫auto deref,就是可以把实现了Deref的类型当成deref之后返回的类型来用,而Box的Deref是这么实现的:
即返回一个&T,而T就是Box指向的那个类型,这样就可以像使用对象本身一样来使用Box包装之后的对象了。
例如后面的
其实应该是
只不过编译器自动做了这件事。
类似的还有个trait叫DerefMut,看名字你应该能猜到它是干啥用的。
不过有一说一Option的as_ref不是Option实现了AsRef trait,而是那个就是一个Option的普通方法,Pin里的as_ref也是一个意思。
--
👇
Orca-bit: 十分感谢
👇
Aya0wind: 如果你是问as_ref为什么是把&Option变成Option<&T>,这个其实就是Option实现的的Asref trait干的事,没啥原因,他就是这么做的,就是一个转换,让你能方便的取到Option内部T的引用。 然后就是你问的Box为什么可以像T那样使用,因为Box实现了一个trait叫Deref,Rust有一个特性叫auto deref,就是可以把实现了Deref的类型当成deref之后返回的类型来用,而Box的Deref是这么实现的:
即返回一个&T,而T就是Box指向的那个类型,这样就可以像使用对象本身一样来使用Box包装之后的对象了。
例如后面的
其实应该是
只不过编译器自动做了这件事。
类似的还有个trait叫DerefMut,看名字你应该能猜到它是干啥用的。
十分感谢
👇
Aya0wind: 如果你是问as_ref为什么是把&Option变成Option<&T>,这个其实就是Option实现的的Asref trait干的事,没啥原因,他就是这么做的,就是一个转换,让你能方便的取到Option内部T的引用。 然后就是你问的Box为什么可以像T那样使用,因为Box实现了一个trait叫Deref,Rust有一个特性叫auto deref,就是可以把实现了Deref的类型当成deref之后返回的类型来用,而Box的Deref是这么实现的:
即返回一个&T,而T就是Box指向的那个类型,这样就可以像使用对象本身一样来使用Box包装之后的对象了。
例如后面的
其实应该是
只不过编译器自动做了这件事。
类似的还有个trait叫DerefMut,看名字你应该能猜到它是干啥用的。
如果你是问as_ref为什么是把&Option变成Option<&T>,这个其实就是Option实现的的Asref trait干的事,没啥原因,他就是这么做的,就是一个转换,让你能方便的取到Option内部T的引用。 然后就是你问的Box为什么可以像T那样使用,因为Box实现了一个trait叫Deref,Rust有一个特性叫auto deref,就是可以把实现了Deref的类型当成deref之后返回的类型来用,而Box的Deref是这么实现的:
即返回一个&T,而T就是Box指向的那个类型,这样就可以像使用对象本身一样来使用Box包装之后的对象了。
例如后面的
其实应该是
只不过编译器自动做了这件事。
类似的还有个trait叫DerefMut,看名字你应该能猜到它是干啥用的。