В golang цикл импорта запрещен, действительно ли этот принцип является хорошим решением?

# #go #import

Вопрос:

Вчера я задал этот вопрос в выпуске github, и один из участников сказал, что я должен задать его на этом сайте, поэтому я просто вставляю свой вопрос в stackoverflow.

Какую версию Go вы используете ( go version )?

$ go версия
go версия go1.17.1 windows / amd64

Воспроизводится ли эта проблема в последней версии?

ДА

Какую операционную систему и архитектуру процессора вы используете ( go env )?

go env Вывод

$ go env 

Что вы сделали?

Я пишу простой код, чтобы попытаться описать реальный мир, но «Цикл импорта не разрешен» приведет к ошибке компиляции. Поэтому я мог только переписать простой код в сложный код.

«Цикл импорта запрещен» — это правильный принцип, но это не принцип, который упрощает код, он делает код более сложным.

Это временный принцип или постоянный принцип?

Он разработан после многих размышлений и обсуждений или только для личных предпочтений?

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

Например, учитель входит в класс, многие ученики входят в класс, затем учитель выбирает ученика a, чтобы спросить, затем ученик b спрашивает учителя. Это обычное простое требование.

Но в golang приведенный ниже код не смог успешно скомпилироваться, потому что цикл импорта не разрешен. Это так странно.

 testgo
│  main.go
│
├─classroom
│      ClassRoom.go
│
├─student
│      Student.go
│
└─teacher
        Teacher.go
 
 // main.go
package main

import (
    "testgo/classroom"
    "testgo/student"
    "testgo/teacher"
)

func main() {
    c := amp;classroom.ClassRoom{}
    t := amp;teacher.Teacher{}
    a := amp;student.Student{}
    b := amp;student.Student{}
    t.Enter(c)
    a.Enter(c)
    b.Enter(c)
    t.Ask(a)
    b.Ask(t)
    print(c)
}
 
 // classroom/ClassRoom.go
package classroom

import (
    "testgo/student"
    "testgo/teacher"
)

type ClassRoom struct {
    Teacher  *teacher.Teacher
    Students []*student.Student
}

func (c *ClassRoom) AddTeacher(t *teacher.Teacher) {
    c.Teacher = t
}

func (c *ClassRoom) AddStudent(s *student.Student) {
    c.Students = append(c.Students, s)
}
 
 // teacher/Teacher.go
package teacher

import (
    "testgo/classroom"
    "testgo/student"
)

type Teacher struct {
    TeacherName string
    InClassRoom *classroom.ClassRoom
}

func (t *Teacher) Enter(c *classroom.ClassRoom) {
    c.AddTeacher(t)
    t.InClassRoom = c
}

func (t *Teacher) Ask(s *student.Student) {

}
 
 // student/Student.go
package student

import (
    "testgo/classroom"
    "testgo/teacher"
)

type Student struct {
    StudentName string
    InClassRoom *classroom.ClassRoom
}

func (s *Student) Enter(c *classroom.ClassRoom) {
    c.AddStudent(s)
    s.InClassRoom = c
}

func (s *Student) Ask(t *teacher.Teacher) {

}
 

Наконец, он скомпилирует ошибку, как показано ниже

 package testgo
    imports testgo/classroom
    imports testgo/student
    imports testgo/classroom: import cycle not allowed
 

Есть и другие примеры.

В реальном мире Кошка ловит Крысу, Крыса убегает от Кошки. package Cat импорт package Rat и package Rat импорт package Cat .

В реальном мире животные едят фрукты, фрукты едят животные. package Animal импорт package Fruit и package Fruit импорт package Animal .

В реальном мире цикл импорта происходит везде.

Но в golang цикл импорта запрещен.

Что вы ожидали увидеть?

включить цикл импорта, как в реальном мире

Что вы увидели вместо этого?

цикл импорта не разрешен

Комментарии:

1. Это постоянный принцип, основанный на тщательном обдумывании. Размещайте взаимозависимые типы в одних и тех же пакетах или используйте интерфейсы для прерывания циклов.

2. Не создавайте крошечные пакеты для отдельных типов.

Ответ №1:

Это правильный и хорошо продуманный принцип. Если вы понимаете и впитываете свой вариант использования, вы можете избежать циклов. Например: — класс student должен иметь только сведения, связанные с учеником, имена, возраст, адрес и т. Д. И т. Д. класс должен иметь такие параметры, как емкость, адрес и т.д. Должен быть отдельный класс с именем schedule .go, который будет содержать отображение класса, ученика и учителя.

Комментарии:

1. Хорошо, спасибо за ответ на вопрос. Поскольку принцип соблюдается, мне придется переписать код, чтобы подчиниться ему, это займет гораздо больше времени, но другого решения нет.

Ответ №2:

Это постоянный принцип. Циклические зависимости увеличивают время компиляции, а GO сильно ориентирован на быстрое время компиляции.

Решением циклической зависимости является введение нового интерфейса в новый пакет. Этот интерфейс должен иметь все методы, которые есть у циклической зависимой структуры, и к которым имеет доступ другая циклическая зависимая структура.

Я нашел четкие заметки об этом https://medium.com/@ishagirdhar/import-cycles-in-golang-b467f9f0c5a0

Комментарии:

1. Хорошо, спасибо за ответ на вопрос. Теперь я знаю, что этот принцип является постоянным. И почти все говорят, что это осторожный принцип. Поэтому я изменю свой код.