我有一个 Swift 函数,它返回两个值的元组。第一个值通常(但并非总是)用作调用者中一段可变状态的“更新”版本(我知道我也可以使用inout它而不是元组,但这使得它更烦人保留旧状态的同时保留新状态)。第二个值是函数生成的通常不可变的返回值,其无意覆盖任何现有的可变状态。
从概念上讲,用法如下:
var state = // initialize
(state, retval1) = process(state)
(state, retval2) = process(state)
(state, retval3) = process(state)
Run Code Online (Sandbox Code Playgroud)
显然,这里的问题是retval1、retval2、 和retval3从未被声明,编译器会生气。
state必须是 avar并且不能重新声明,所以我不能写
let (state, retval) = process(state)
Run Code Online (Sandbox Code Playgroud)
但是,retval永远不会被修改,并且应该let作为最佳实践和良好编码风格的问题来声明。
我希望以下语法可能有效,但事实并非如此:
(state, let retval) = process(state)
Run Code Online (Sandbox Code Playgroud)
我应该如何解压/解构这个元组?
如果我猜对了std::rc::Rc,就不可能在 Rust 中通过a创建可变借用,您必须使用Cell或RefCell。但无论如何我无法理解如何使用它们。例如考虑这个简单的例子:
use std::cell::RefCell;
struct X (i32);
impl X {
fn foo(&mut self) {
self.0 = 0;
}
}
fn main () {
let x = X(5);
let rcx = RefCell::new(&x);
let mut mutx: std::cell::RefMut<&X> = rcx.borrow_mut();
(*mutx).foo();
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
16:5: 16:9 error: cannot borrow immutable local variable `mutx` as mutable
16 mutx.foo();
Run Code Online (Sandbox Code Playgroud)
但是,如果我从行中删除引用(并更新类型mutx):
let rcx = RefCell::new(x);
Run Code Online (Sandbox Code Playgroud)
一切安好。但我不明白为什么,因为RefMut::deref_mut() -> &mut T在第 16 …
如果这很简单,请道歉。我正在学习 rust 并习惯奇怪的借用系统。通常,您只需更改方法调用的语法即可获得所需的行为,但是,在这种情况下,现在似乎有办法了。
我的代码的简化版本是这样的:EventPumpif from SDL。
struct Example {
pump: EventPump
}
impl Example {
fn method(&mut self) {
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到以下错误:
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\game.rs:53:67
|
30 | for event in self.pump.poll_iter();
| ---------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
53 | self.other_method();
| ^^^^ immutable borrow …Run Code Online (Sandbox Code Playgroud) 我知道 Rust 引用很像 C 指针,并且我一直将 Rust 引用视为 C 指针。经过一些实验和搜索,我很困惑。
\n我熟悉 C,并且读过What\'s the Difference between Placeing \xe2\x80\x9cmut\xe2\x80\x9d before a variable name and after the \xe2\x80\x9c:\xe2\ x80\x9d?,给出下表:
\n\n\n …Run Code Online (Sandbox Code Playgroud)\n// Rust C/C++\n a: &T == const T* const a; // can\'t mutate either\nmut a: &T == const T* a; // can\'t mutate what is pointed to\n a: &mut T == T* const a; // can\'t mutate pointer\nmut a: &mut T == T* a; // can mutate both\n
我时不时地会遇到在循环内借用(或不借用)可变变量的相同问题,最后我坐下来编译了一个最小的示例。因此,代码有点愚蠢,但这是我能想到的最短版本,突出了问题:
\nstruct Association {\n used: bool,\n key: usize,\n value: String,\n}\n\nimpl Association {\n fn new(key: usize, value: &str) -> Self {\n Association{used: false, key: key, value: value.to_string()}\n }\n}\n\nfn find_unused<\'a>(data: &\'a mut Vec<Association>) -> Option<&\'a String> {\n for k in 0.. {\n for a in data {\n if a.key == k && !a.used {\n a.used = true;\n return Some(&a.value);\n }\n }\n }\n None\n}\n\nfn main() {\n let mut assoc = vec![\n Association::new(7, "Hello"),\n Association::new(9, "World")\n ];\n\n println!("{}", find_unused(&mut assoc).unwrap());\n println!("{}", find_unused(&mut assoc).unwrap());\n}\n …Run Code Online (Sandbox Code Playgroud) 是否有一个C#等同于Python的id()?如果没有,我如何测试对象是否已更改?例如,在Python中,一个不可变对象:
>>> s = "abc"
>>> id(s)
11172320
>>> s += "d"
>>> id(s)
18632928
Run Code Online (Sandbox Code Playgroud)
一个可变的:
>>> a = [1, 2, 3]
>>> id(a)
11259656
>>> a += [4]
>>> id(a)
11259656
Run Code Online (Sandbox Code Playgroud)
编辑 - 到目前为止,大多数答案都是关于比较函数/运算符,但我对正在比较的值更感兴趣.我最初并不清楚这一点,我接受Object.ReferenceEquals了答案.
我已经读过F#中的值是不可变的.但是,我也遇到了重新定义值定义的概念,它影响了以前的定义.这与可变值有什么不同?我这不仅仅是作为理论构造,而且还有关于何时使用可变值以及何时重新定义表达式的建议; 或者如果有人能够指出后者不是惯用的f#.
重新定义的基本示例:
let a = 1;;
a;; //1
let a = 2;;
a;; //2
Run Code Online (Sandbox Code Playgroud)
更新1:
添加到下面的答案中,顶级Fsharp交互式中的重新定义仅允许在不同的终端中.以下将在fsi中引发错误:
let a = 1
let a = 2;;
Error: Duplicate definition of value 'a'
Run Code Online (Sandbox Code Playgroud)
另一方面,let绑定允许重新定义.
更新2:实际差异,闭包不能使用可变变量:
let f =
let mutable a = 1
let g () = a //error
0
f;;
Run Code Online (Sandbox Code Playgroud)
更新3:
虽然我可以使用refs模拟副作用,例如:
let f =
let a = ref 1
let g = a
a:=2
let x = !g + !a
printfn "x: %i" x //4
f;;
Run Code Online (Sandbox Code Playgroud)
我不太清楚重新定义和使用mutable关键字之间的实际区别,除了使用闭包的区别,例如:
let f = …Run Code Online (Sandbox Code Playgroud) 我想对&mut [u8]做一些操作.
在我的测试代码中,我有:
#[test]
fn test_swap_bytes() {
let input: &[u8] = b"abcdef";
let result: &mut[u8] = ?;
do_something(result);
assert_eq!(b"fedcba", result);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如何轻松获得可变的u8切片?我该怎么把问号放在哪里?
这是一个错误还是这里有一个微妙的教训?
NSNumber *someNumber = @(1);
[someNumber respondsToSelector:@selector(mutableCopy)]; // returns YES (!)
[someNumber respondsToSelector:@selector(mutableCopyWithZone:)]; // returns NO
Run Code Online (Sandbox Code Playgroud)
Apple LLVM 7.1(iOS SDK 9.3)
我玩弄了ValueTuple结构并试图实现一个不可变的复合键.密钥由值类型组成.
我尝试用一些单元测试打破以下实现,到目前为止还没有成功.我错过了什么吗?
这也只是出于好奇,我想ValueTuple在.NET 4.7发布之前得到s和它的局限性.
到目前为止,我对a的理解ValueTuple是它只作为变量而不是作为字段或属性变化.不知道"可变"在这里意味着什么.更改ValueTuple实例实际上是否创建了一个新的ValueTuple(就像它的常识一样,字符串是"不可变的"但实际上是引用类型)?
从这个答案
System.ValueTuple不仅是一个struct,它是一个可变的,并且在使用它们时必须要小心.想想当一个班级System.ValueTuple作为一个领域时会发生什么.
在这里我的实施和测试
public interface IHaveCompositeKey
{
(Guid id, string name) Key { get; }
}
public class ImmutableKey : IHaveCompositeKey
{
public (Guid id, string name) Key { get; }
public ImmutableKey((Guid id, string name) key) => Key = key;
public override int GetHashCode() => Key.GetHashCode();
public override bool Equals(object obj)
{ …Run Code Online (Sandbox Code Playgroud) mutability ×10
rust ×5
c# ×2
immutability ×2
reference ×2
borrowing ×1
coding-style ×1
copy ×1
f# ×1
iterator ×1
nsnumber ×1
objective-c ×1
python ×1
slice ×1
swift ×1
tuples ×1
valuetuple ×1