Изменение типа не ведет себя так, как ожидалось - PullRequest
0 голосов
/ 02 апреля 2020

Я решал вопрос о кодировании, который спрашивал, проверяет ли данный массив все вращения данной строки, и я изначально придумал это решение:

type myArr []string

func ContainAllRots(strng string, arr []string) bool { 
   if strng == "" {
      return true
    }

   arr = myArr(arr)

   for i := 0; i < len(strng); i++ {
      if !arr.Contains(strng[i:] + strng[:i]) {
        return false
      }
    }

    return true
}

func (a myArr) Contains(strng string) bool {
  for _,s := range a {  
    if s == strng {
      return true
    }
  }

  return false

}

Пожалуйста, игнорируйте тот факт, что это может не будет лучшим / наиболее эффективным решением данной проблемы, но да, поэтому я получаю это сообщение об ошибке:

arr.Contains undefined (type []string has no field or method Contains)

Я думал, что со строкой arr = myArr(arr) Я буду менять типа arr и, следовательно, иметь возможность вызывать метод Contains для него, но я предполагаю, что logi c не работает. Может кто-нибудь сказать мне, что здесь происходит под капотом и почему я не назначаю свой новый пользовательский тип обратно arr?

Ответы [ 2 ]

3 голосов
/ 02 апреля 2020

«Проблема»

Go - это, по большей части, язык с системой типов stati c (или «с типизацией stati c»).
Среди прочих В сущности, это означает, что любая переменная в программе имеет тип неявный , с которым была объявлена ​​переменная .
То есть, другими словами, тип переменной не сохраняется каким-либо образом in it, и, следовательно, не может быть изменено путем присвоения ему значения другого типа.

Следовательно, если у вас есть

type myArr []string

func foo(arr []string) {
    arr = myArr(arr)
}

Назначение недопустимо, так как в противном случае это будет означать изменение типа переменной arr на myArr.

Что вы можете с этим поделать?

Подход, используемый в этом случае, заключается в простом использовании другой переменной подходящий тип.

Это может выглядеть как растрата ресурсов, но

  • Такая трата незначительна, и в любом случае не оптимизируйте, что не является медленным.
  • переназначение, которое вы пытались сделать, может выглядеть аккуратно, но в то же время Читатель: поскольку одна и та же переменная будет иметь различные наборы методов до и после присваивания.

Для полноты следует отметить, что Go имеет специальные средства, которые позволяют программисту фактически иметь переменные, которые может изменить свой тип во время выполнения; эти средства обеспечиваются интерфейсами.

Например, оба назначения в приведенном ниже коде совершенно законны:

type I interface {
  Foo()
}

type A struct{}

func (a A) Foo() {}

type B struct{}

func (b B) Foo() {}

var v I

v = A{}
v = B{}

Переменная v имеет тип I, который является типом интерфейса, и поэтому он должен содержать значения интерфейса.
Оба назначения изменяют так называемый dynamici c тип переменной v - до A, а затем до B соответственно, в то время как его тип stati c остается I.

Я бы отметил, что в вашем конкретном случае использование интерфейсов не требуется, но это что-то узнать о.

1 голос
/ 02 апреля 2020

arr был объявлен типа []string из-за сигнатуры функции ContainAllRots. Это можно исправить, используя другое имя для arr слева от назначения в arr = myArr(arr).

Например:

type myArr []string

func ContainAllRots(strng string, arr []string) bool {
    if strng == "" {
        return true
    }

    mArr := myArr(arr)

    for i := 0; i < len(strng); i++ {
        if !mArr.Contains(strng[i:] + strng[:i]) {
            return false
        }
    }

    return true
}

func (a myArr) Contains(strng string) bool {
    for _, s := range a {
        if s == strng {
            return true
        }
    }

    return false

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...