我正在尝试在 FreeBSD 12 下测试 Rust 1.39 中的一些语言功能,与 Free Pascal 3.0.4 相比,以使用字符串键寻址的 2D 点的简单通用点集合。不幸的是,泛型类型声明的代码没有在很早的状态下编译并停止:
error[E0106]: missing lifetime specifier
--> src/main.rs:11:31
|
11 | type TPointMap = BTreeMap<&TString, TPoint>;
|
Run Code Online (Sandbox Code Playgroud)
我该如何重写 Rust 代码?
细节:
为了测试语言行为,我用 Rust 和 Pascal 编写了两个小程序,以“语法上”处理相同的上下文。Pascal 程序是一个简单的声明:
STDIO program test;
uses fgl; { Use the free pascal generics library }
type
TDouble = Double; { Define a 64 bit float }
TString = String; { Define a string type }
TPoint = record { Define a point record }
X : TDouble; { Coordinate X }
Y : TDouble; { Coordinate Y }
end;
{ Define a map of points with strings as key }
TPointMap = specialize TFPGMap<TString, TPoint>;
{ Test program }
var
map : TPointMap; { Declare the map variable }
point : TPoint; { Declare a point variable }
found : TPoint; { Varaiable for a found point }
key : TString; { Variable to address the point in the map }
begin
map := TPointMap.create; { Allocate a new ma container }
with point do begin { Set the point variable }
x := 1.0; y := 2.0;
end;
key := '123'; { Set the key address to '123' }
map.add(key,point); { Store the point in the map }
{ Search the point an write the result in the rusty way }
case map.TryGetData(key, found) of
true : writeln('X: ',found.X:2;, ' Y:', found.Y:2:2);
false : writeln('Key ''',key,''' not found');
end;
map.free; { De-allocate the map }
{ Plain types are de-allocated by scope }
end.
Run Code Online (Sandbox Code Playgroud)
该程序编译并给我:
$ ./main
X: 1.00 Y:2.00
Run Code Online (Sandbox Code Playgroud)
这是我不正确的 Rust 版本代码:
$ ./main
X: 1.00 Y:2.00
Run Code Online (Sandbox Code Playgroud)
备注:我知道由于借用和所有权的概念,某些代码行不能在 Rust 代码中使用。线
match map.get(&key)...
Run Code Online (Sandbox Code Playgroud)
是其中之一。
大致相当于freepascal版本,TString应该是String而不是str. 甲freepascal字符串是(依赖于一些标志)的指针,一个长度和字符的堆分配阵列。这(几乎)正是如此String。str只是字符数组并且未调整大小,因此它始终必须位于某种(胖)指针之后。
一旦进行了更改,只需要做一些其他事情来修复代码。TPointMap需要一个生命周期参数,因为它使用引用类型。引用的生命周期必须来自某个地方,所以我们TPointMap在那个生命周期中使用泛型。
type TPointMap<'a> = BTreeMap<&'a TString, TPoint>;
Run Code Online (Sandbox Code Playgroud)
BTreeMap<TString, TPoint>如果您的用例允许,您也可以考虑简单地使用。
我们需要做一些转换来声明key: TString. 字符串文字有 type 'static str,但有一个简单的to_string方法可以将它们转换为Strings。
let key: TString = "123".to_string();
Run Code Online (Sandbox Code Playgroud)
最后,有一个错字found.X。
Some(found) => println!("X: {} Y: {}", found.x, found.y),
Run Code Online (Sandbox Code Playgroud)
总之,我们有
use std::collections::BTreeMap; // Use a map from the collection
type TDouble = f64; // Define the 64 bit float type
type TString = String; // Define the string type
struct TPoint {
// Define the string type
x: TDouble, // Coordinate X
y: TDouble, // Coordinate Y
}
// Define a map of points with strings as key
type TPointMap<'a> = BTreeMap<&'a TString, TPoint>;
// Test program
fn main() {
let point = TPoint { x: 1.0, y: 2.0 }; // Declare and define the point variable
let mut map = TPointMap::new(); // Declare the map and allocate it
let key: TString = "123".to_string(); // Declare and define the address of point
map.insert(&key, point); // Add the point to the map
// search the point and print it
match map.get(&key) {
Some(found) => println!("X: {} Y: {}", found.x, found.y),
None => println!("Key '{}' not found", key),
}
// map is de-allocated by scope
}
Run Code Online (Sandbox Code Playgroud)