Home > OS >  invalid operation: cannot index T when modeling slices of arbitrary dimensions
invalid operation: cannot index T when modeling slices of arbitrary dimensions

Time:07-22

I am try to do a matrix subtraction with unknow size of matrix. here is the code:

type ArrayLike interface {
    []interface{} | [][]interface{} | [][][]interface{} | [][][][]interface{}
}

func subMatrix[T ArrayLike](A, B T, shape []int) interface{} {

    dim := shape[0]
    if len(shape) == 1 {
        retObj := make([]interface{}, dim)
        for i := 0; i < dim; i   {
            Av := A[i].(float64)
            Bv := B[i].(float64)
            retObj[i] = Av - Bv
        }
        return retObj
    } else {
        retObj := make([]interface{}, dim)
        for i := 0; i < dim; i   {
            retObj[i] = subMatrix(Av[i], Bv[i], shape[1:])
        }
        return retObj
    }
}

It complains about

invalid operation: cannot index A (variable of type T constrained by []interface{}|[][]interface{}|[][][]interface{}|[][][][]interface{})compilerNonIndexableOperand

Does anyone know how to do this job?

CodePudding user response:

You can't do this, not with generics and not with interface{}/any alone. The main issue is that you can't statically model slices with arbitrary dimensions — i.e. arbitrary types. Let's go in order:

The error message you got is because you can't index a type parameter with a union constraint like that. Specs, Index expressions:

For a of type parameter type P:

  • [...]
  • The element types of all types in P's type set must be identical. [...]

The element types of ArrayLike's type set are not identical. The element type of []interface{} is interface{}, the one of [][]interface{} is []interface{} and so on.

There is a placebo solution to the indexing error, outlined here, basically it involves changing the type of the arguments A and B to a slice []T. Then you can index A[i] and B[i].

However this isn't enough. At this point, there's no way to pass correct arguments to the recursive call. The type of the expression A[i] is now T, but subMatrix wants []T.

Even dropping type parameters and declaring the args A and B as any doesn't work, because on the recursive call you still want to index them. In order to index, you have to assert any to something that's indexable, but what would that be? At each recursion the types would have one less dimension, so a statically typed assertion would eventually panic.

The only way to solve this is (probably?) with reflection, but honestly I don't see a practical utility to do that.

You can, and should, write a generic function for each matrix dimension:

import "golang.org/x/exp/constraints"

type Number interface {
    constraints.Integer | constraints.Float
}

func Sub2DMatrix[T Number](a, b [][]T) {
    for i := range a {
        for j := range a[i] {
            a[i][j] -= b[i][j]
        }
    }
}
  • Related