# Possible to have a multidimensional array parameter of unknown size?

**URL:** <https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631>\
**Category:** help\
**Created:** [May 29, 2015, 8:00pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631 "2015-05-29T20:00:14Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![bquinlan](https://avatars.discourse-cdn.com/v4/letter/b/58f4c7/32.png) [@bquinlan](https://users.rust-lang.org/u/bquinlan)\
**Post date:** [May 29, 2015, 8:00pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/1 "2015-05-29T20:00:14Z")

</div>

Is it possible to write a function that takes in a multidimensional array of unknown size? For example:

fn something(grid: &[[char; 7]; 7]) ...

But without specifying the sizes?

Cheers,  
Brian

---

<div class="post-metadata">

**Author:** ![eminence](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/eminence/32/5649_2.png) [@eminence](https://users.rust-lang.org/u/eminence)\
**Post date:** [May 29, 2015, 10:05pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/2 "2015-05-29T22:05:09Z")

</div>

In rust, an "Array" is always a fixed size. The canonical way to represent a list of things of unknown size is a `Vec<T>`. A multidimensional vector could be `Vec<Vec<T>>`.

---

<div class="post-metadata">

**Author:** ![bquinlan](https://avatars.discourse-cdn.com/v4/letter/b/58f4c7/32.png) [@bquinlan](https://users.rust-lang.org/u/bquinlan)\
**Post date:** [May 29, 2015, 10:52pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/3 "2015-05-29T22:52:08Z")

</div>

I understand that Arrays have a fixed size. I'm wondering if it is possible to write generic functions to process them.

---

<div class="post-metadata">

**Author:** ![ogeon](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ogeon/32/226_2.png) [@ogeon](https://users.rust-lang.org/u/ogeon)\
**Post date:** [May 30, 2015, 12:53pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/4 "2015-05-30T12:53:53Z")

</div>

It is possible. You can abstract them as something that can be referenced to as `&[T]`:

```rust
use std::fmt::Display;

fn print_matrix<Matrix: AsRef<[Row]>, Row: AsRef<[T]>, T: Display>(matrix: Matrix) {
    let matrix = matrix.as_ref();
    println!("[");
    
    for row in matrix {
        let row = row.as_ref();
        let mut first = true;
        print!("\t[");
        
        for element in row {
            if !first {
                print!(", {}", element);
            } else {
                print!("{}", element);
                first = false;
            }
        }
        
        println!("; {}]", row.len());
    }
    
    println!("; {}]", matrix.len());
}

fn main() {
    print_matrix([[1; 7]; 7]);
}

```

The generic type `Matrix` can be referenced to as a slice of `Row` and `Row` can be referenced to as a slice of `T`. You can replace `T` with `char` or whatever else you want. This should also work with `Vec<Vec<T>>` and any combination of vectors and arrays.

---

<div class="post-metadata">

**Author:** ![excess](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/excess/32/830_2.png) [@excess](https://users.rust-lang.org/u/excess)\
**Post date:** [May 30, 2015, 7:58pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/5 "2015-05-30T19:58:13Z")

</div>

> [@ogeon](#):
>
> fn main() {  
> print\_matrix([[1; 7]; 7]);  
> }

Is this copying the nested array valued argument on the stack by value? Or is the AsRef magic telling the compiler it can pass a reference to the data?

---

<div class="post-metadata">

**Author:** ![ogeon](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ogeon/32/226_2.png) [@ogeon](https://users.rust-lang.org/u/ogeon)\
**Post date:** [May 30, 2015, 9:49pm UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/6 "2015-05-30T21:49:07Z")

</div>

The `[v; N]` syntax copies the value `v` `N` times in an array, so `[[1; 7]; 7]` results in an array of length 7, containing arrays of length 7, containing a number 1 in each element. Basically an 7 by 7 grid of ones.

`AsRef` is used to make referencing generic. We know that all arrays implements `AsRef<[T]>`, so it's perfect here because we want to make the fixed length generic and a slice allows us to make the type independent of length. The signatures says that we want something that we can take a reference to and we want the type of the reference to be `&[T]`. We don't care if it's an array or anything else, as long as we can get a slice into it, because that's all we need.

Did that answer your question?

---

<div class="post-metadata">

**Author:** ![excess](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/excess/32/830_2.png) [@excess](https://users.rust-lang.org/u/excess)\
**Post date:** [May 31, 2015, 12:54am UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/7 "2015-05-31T00:54:11Z")

</div>

> [@ogeon](#):
>
> Did that answer your question?

Heh, not really, but I appreciate the effort 😄

My basic question: Is the argument passed by value? Or is the argument converted to a reference **before** being passed to the function?

I have some other questions, if you're willing. Here's a pared down version of your example:

```
use std::fmt::Display;
fn hmm<Row: AsRef<[T]>, T: Display>(row: Row) {
    let row = row.as_ref();
    for ele in row {
        print!(" {}", ele);
    }
    print!("\n");
}
 
fn main() {
    let a = [0f64; 7];
    hmm(a);
}

```

Why isn't this next signature equivalent?

```
fn hmm<T: Display>(row: AsRef<[T]>) {

```

I think I'm not understanding how type substitution works with template arguments. The first says Row implements a trait, the second says `row` is an instance of the trait? I can make it work if I change to:

```
fn hmm<T: Display>(row: &AsRef<[T]>) {

```

and call it with

```
hmm(&a);

```

But I don't understand why the original version doesn't need to take the reference to a.

This last question is niddly... If I switch the 7 to 77, there isn't a predefined AsRef implementation (they go up to 32). I tried to add one, but it complained about adding traits to types that weren't in my crate. So the brief question is: how do you make the next one work? (without switching to a Vec)

```
fn main() {
    let a = [0f64; 77];
    hmm(a);
}

```

Thanks in advance for any answers.

---

<div class="post-metadata">

**Author:** ![ogeon](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/ogeon/32/226_2.png) [@ogeon](https://users.rust-lang.org/u/ogeon)\
**Post date:** [May 31, 2015, 11:00am UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/8 "2015-05-31T11:00:10Z")

</div>

> [@excess](#):
>
> My basic question: Is the argument passed by value? Or is the argument converted to a reference before being passed to the function?

Ah, oh, I get it now. Yes, it's passed by value. Generic type parameters are treated like any type, with the difference that you don't actually know what they are, so a reference would instead be `&Matrix`. Rust will generate different variants of the function for different types, so it's all compile time. I can recommend [the part about generics](https://doc.rust-lang.org/book/generics.html) in The Book if you want more details.

> [@excess](#):
>
> I have some other questions, if you're willing.

Sure 😄 I hope you don't mind if I keep recommending further reading. You are still welcome to ask questions.

> [@excess](#):
>
> Why isn't this next signature equivalent?

Because `AsRef<[T]>` is a trait and a trait has no known size at compiletime. You would have to pass it as a pointer of some sort, like `&AsRef<[T]>` or `Box<AsRef<[T]>>`. Using a generic type instead is like saying "I don't care what it is, as long as it implements these traits` and the compiler will generate an appropriate concrete function for us. You can read more about this in [the part about trait objects](https://doc.rust-lang.org/book/trait-objects.html).

> [@excess](#):
>
> So the brief question is: how do you make the next one work? (without switching to a Vec)

That's a bit more tricky. You can't, as you observed, implement someone else's trait for someone else's type. There are generally two options in such a case: make a wrapper type, like `struct Array77<T>([T; 77]);`, and implement what you want for it, or make your own conversion trait and use it instead of `AsRef`. Both of these has their ups and downs, so what you choose depends on what you want to achieve. I think the custom trait would make more sense in this case, since you can make it work for things that implement `AsRef<[T]>`, as well.

The solution for this particular situation is actually simpler. You can cast a reference to your array to a `&[T]` instead and pass that to the function. Any reference to an array can be turned into a slice, so we are pretty lucky in this case:

```rust
fn main() {
    let a = [0f64; 77];
    hmm(&a as &[f64]);
}

```

`AsRef<T>` is always implemented for `T`, meaning that `AsRef<[T]>` is implemented for `[T]`, so this works.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [January 12, 2023, 8:36am UTC](https://users.rust-lang.org/t/possible-to-have-a-multidimensional-array-parameter-of-unknown-size/1631/9 "2023-01-12T08:36:57Z")

</div>

Closed on January 12, 2023, 8:36am UTC


