在Go或Rust中,数组的数组应该如何表示?

huangapple go评论79阅读模式
英文:

Array of arrays in Go or Rust?

问题

我正在将一些旧的 PHP 脚本转换为 Go,以实现更好的性能。然而,旧的 PHP 脚本中充斥着多维数组。以下是代码库中的一部分代码:

while (($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
    $someData[$row['column_a']][$row['column_b']] = $row;
}

// ... 更多查询和其他操作

if (isset($moreData['id']) && isset($anotherData['id']) && $someData[$anotherData['id']][$moreData['id']]) {
    echo $someData[$anotherData['id']][$moreData['id']];
}

很糟糕,我知道,但我不能改变逻辑。通过使用 phc 进行编译,我使整个脚本的性能得到了很大的提升,但是转移到一种过程化、静态类型的语言似乎是一个更好的选择。如何在 Go 或 Rust 中高效地复制这些数据结构?在检查索引时需要具有容错能力,脚本中到处都有 isset 来检查数据结构中的标识符是否存在。

英文:

I'm porting some old PHP script to Go in order to achieve better performance. However, the old PHP is full of multidimensional arrays. Some excerpt from the codebase:

while (($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
	$someData[$row['column_a']][$row['column_b']] = $row;
}

// ... more queries and stuff

if (isset($moreData['id']) && isset($anotherData['id']) && $someData[$anotherData['id']][$moreData['id']]) {
	echo $someData[$anotherData['id']][$moreData['id']];
}

Awful, i know, but i can't change the logic. I made the whole script perform much better by compiling with phc, but moving to a procedural, statically-typed language seems like a better move. How can i replicate those data structures efficiently with Go or Rust? It needs to be fault-tolerant when it comes to checking indexes, there's a lot of issets all around the script to check if the identifiers exist in the data structures.

答案1

得分: 4

在Go语言中,这可以用map表示。语法是map[key]value。例如,要存储一个多维映射[string, string] -> int,可以使用map[string]map[string]int。如果你知道索引是整数且密集排列的,那么你应该使用切片。切片更简单,形式为[][]type

至于检查键是否存在,可以使用以下语法,其中m是一个映射:

if val, ok := m[key1][key2]; ok {
    // 对val进行操作
}

请记住,在向多维映射添加键之前,必须确保内部映射已分配。

if _, ok := m[key]; !ok {
    m[key] = make(map[string]int)
}
m[key1][key2] = value

显然,你可能希望将此封装在具有方法或几个简单函数的类型中。

英文:

In Go, this would be represented as a map. The syntax is map[key]value. So for example to store a multidimensional map of [string, string] -> int it would be map[string]map[string]int. If you know your indices are integers and densely packed, then you'd want to use slices. Those are simpler and look like [][]type.

As for the checking for a key existing, use this syntax, where m is a map:

if val, ok := m[key1][key2]; ok {
    ///Do something with val
}

Remember that to add a key to a multidimensional map you'd have to make sure the inner map is allocated before adding to it.

if _, ok := m[key]; !ok {
    m[key] = make(map[string]int)
}
m[key1][key2] = value

Obviously you'd want to wrap this up in a type with methods or a few simple functions.

答案2

得分: 3

Rust

PHP数组实际上是关联数组,也被称为映射字典。Rust在其标准库中使用名称MapMap trait提供了各种实现的接口。特别地,这个trait定义了一个contains_key方法,你可以用它来检查映射是否包含特定的键(而不是写isset($array[$key]),你写map.contains_key(key))。

Map有两个类型参数:K是映射的键的类型(即你用作索引的值),V是映射的值的类型。

如果你的映射需要包含不同类型的键和/或值,你需要使用Any trait。例如,如果键是字符串,值是不同类型的值,你可以使用HashMap<String, Box<Any>>Box是必需的,因为trait对象是不定大小的;参见这个答案获取更多信息)。查看AnyRefExtAnyMutRefExt的文档,了解如何处理Any值。

然而,如果可能的类型相对有限,你可能更容易定义自己的trait,并在需要使用这些值的所有地方都使用该trait,而不必在每个地方都显式地进行类型转换(此外,你可以通过添加impl来添加类型,而无需更改使用值的所有地方)。

英文:

Rust

PHP arrays are actually associative arrays, also known as maps or dictionaries. Rust uses the name Map in its standard library. The Map trait provides an interface for a variety of implementations. In particular, this trait defines a contains_key method, which you can use to check if the map contains a particular key (instead of writing isset($array[$key]), you write map.contains_key(key)).

Map has two type parameters: K is the type of the map's keys (i.e. the values you use as an index) and V is the type of the map's values.

If you need your map to contain keys and/or values of various types, you'll need to use the Any trait. For example, if the keys are strings and the values are of various types, you could use HashMap<String, Box<Any>> (Box is necessary because trait objects are unsized; see this answer for more information). Check out the documentation for AnyRefExt and AnyMutRefExt to see how to work with an Any value.

However, if the possible types are relatively limited, it might be easier for you to define your own trait and use that trait instead of Any so that you can implement operations on those types without having to cast explicitly everywhere you need to use the values (plus, you can add types by adding an impl without having to change all the places that use values).

huangapple
  • 本文由 发表于 2014年10月5日 02:58:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/26196091.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定