Есть ли идиоматический способ индексирования через интерфейс типа утвержденного в Go? - PullRequest
0 голосов
/ 23 сентября 2019

Я работаю над реализацией одновременного чтения string и byte в Go.Цель этого - разрешить синтаксический анализ newline и других подобных байтов в строках чтения.

При исследовании этой проблемы я нашел различные способы обработки нескольких значений в контексте одного значения 1, однако ни один из них не имеет отношения к появлению смешанных типов.Идея использования интерфейса для решения этой проблемы была предложена 2 , и была предпринята попытка, но меня не устраивает длинное многословие существующих предложений 3 и 4.

Интересно, существует ли идиоматический способ эффективной сортировки множества типизированных значений аккуратно.

РЕДАКТИРОВАНИЕ: Сначала я установил интерфейс, как было предложено.Это кажется хорошей идеей, и, если я помню, это часто используемый трюк из Си.

func Use(vals ...interface{}) {
    i := 0
    p := []uint8{}  //I've replaced the alias "byte" with the native "uint8"
    var val uint8  //I've changed this declaration to a non-assigned declaration
    for i, val := range vals {
        if i < 1 {
            _ = val
            i++
        } else {
            p[i] = val.(uint8)
            return fmt.Print(p[i]) //please excuse the earlier typo
            //interestingly, this call to p[i] returns more than one value
        }
    }
}

Остальная часть основного кода следует:

func other() (string, []byte) {
    a := "declared and not used"
    b := []byte("stuff")
    return a,b
}

func main() {
    Use(other())
}

Для меня это остается неизвестным, почемуэтот код должен иметь несколько значений внутри p [i].Разве blank identifier, используемый в контуре управления, не делает такую ​​возможность маловероятной?

Новая ошибка отредактированного кода сообщается как: invalid type assertion: x.(uint8) (non-interface type func(...interface {}) []interface {} on left)

Исходный код может бытьнаходится по адресу: https://play.golang.org/p/BEhOT7R0vvr

Отредактированный код можно найти по адресу: https://goplay.space/#SF7X7dx8yL9

Ответы [ 2 ]

1 голос
/ 23 сентября 2019
        return fmt.print(p[i]) 
        //interestingly, this call to p[i] returns more than one value

Нет, это не так.

Фактически, компилятор не знает, сколько элементов он возвращает, потому что fmt.printf не экспортируетсятак что он не знает, что это такое.Все, что он знает, это то, что он возвращает одно или несколько значений.Но вы находитесь в функции с нулевыми возвращаемыми значениями, поэтому возникает ошибка.

Неясно, что вы хотите, поэтому я не уверен, как предложить изменить код, но два возможных ответа кажутся очевидными:

  1. Прекратите возвращать что-либо:

        fmt.Print(p[i])
        return
    
  2. Измените свою функцию, чтобы вернуть что-то, затем вызовите соответствующую функцию:

    func Use(vals ...interface{}) byte {
      // ... skip
          return p[i]
    
0 голосов
/ 23 сентября 2019

Когда вы вызываете Use(other()), вы передаете два параметра в Use переменный параметр: a string и a []byte.Таким образом, когда вы перебираете их, первая итерация дает вам string, вторая итерация дает вам []byte.Также большая часть этого кода не нужна и должна давать сбой (некоторые во время компиляции, некоторые во время выполнения):

// this declares a variable in function scope that is never used; it's immediately shadowed
val := []byte("")
// this declares a *new* variable val in loop scope, shadowing the outer val
for i, val := range vals {
    if i < 1 {
        // this does absolutely nothing
        _ = val
        // this also does absolutely nothing - i is the loop iterator and is overwritten by range on every iteration
        i++
    } else {
        // this should be hard failing because there is no case where val is a byte; it's only ever string or []byte
        p[i] = val.(byte)
        // It's fmt.Print - fmt.print would be unexported and not usable
        return fmt.print(p[i])
    }
}
...