Разгледайте концепцията за отражение в езика за програмиране Go, като се задълбочите в мощните му възможности за динамичен анализ и манипулиране на код.

Програмният език Go е широко известен със своята изразителност. Това е строго типизиран език, но все пак дава на приложенията възможност динамично да манипулират и инспектират обекти, включително променливи, функции и типове по време на изпълнение.

Отражението е механизмът, който Go използва, за да постигне тази способност. Какво тогава е отражението и как можете да приложите отражение във вашите Go приложения?

Какво е отражение?

Отражението е способността на програмата да изследва своите променливи и структура и да ги манипулира по време на изпълнение.

Отражението в Go е механизъм, който езикът предоставя за динамично манипулиране на типове и обекти. Може да се наложи да изследвате обекти, да ги актуализирате, да извиквате техните методи или дори да извършвате операции, които са естествени за техните типове, без да знаете техните типове по време на компилация. Отражението прави всичко това възможно.

instagram viewer

Различни пакети в Go включително кодиране което ви позволява да работа с JSON, и fmt, разчитат в голяма степен на отражение под капака, за да изпълняват задълженията си.

Разбиране на отразяващия пакет в Go

Изучаване на Golang може да бъде предизвикателство поради своята семантика и стабилната библиотека от пакети и методи, които улесняват разработването на ефективен софтуер.

The отразявам пакет е един от тези много пакети. Състои се от всички методи, от които се нуждаете, за да приложите отражение в Go приложения.

За да започнете с отразявам пакет, можете просто да го импортирате по този начин:

import"reflect"

Пакетът дефинира два основни типа, които поставят основата за размисъл в Go: отразявам. Тип и отразявам. Стойност.

А Тип е просто тип Go. отразявам. Тип е интерфейс, който се състои от различни методи за идентифициране на различни типове и изследване на техните компоненти.

Функцията за проверка на типа на всеки обект в Go, отразявам. Тип, приема всяка стойност (an интерфейс{}) като единствен аргумент и връща a отразявам. Тип стойност, която представлява динамичния тип на обекта.

Кодът по-долу демонстрира използването на отразявам. Тип:

x := "3.142"
y := 3.142
z := 3
typeOfX := reflect.TypeOf(x)
typeOfY := reflect.TypeOf(y)
typeOfZ := reflect.TypeOf(z)
fmt.Println(typeOfX, typeOfY, typeOfZ) // string float64 int

Вторият тип в отразявам пакет, отразявам. Стойност може да съдържа стойност от всякакъв тип. The отразявам. Стойност на функция приема всякакви интерфейс{} и връща динамичната стойност на интерфейса.

Ето пример, показващ как да използвате отразявам. Стойност на за да проверите стойностите по-горе:

valueOfX := reflect.ValueOf(x)
valueOfY := reflect.ValueOf(y)
valueOfZ := reflect.ValueOf(z)
fmt.Println(valueOfX, valueOfY, valueOfZ) // 3.142 3.142 3

За да проверите видовете и типовете стойности, можете да използвате Мил и Тип метод като този:

typeOfX2 := valueOfX.Type()
kindOfX := valueOfX.Kind()
fmt.Println(typeOfX2, kindOfX) // string string

Въпреки че резултатът от двете извиквания на функции е един и същ, те са различни. typeOfX2 е основно същото като typeOfX защото и двете са динамични отразявам. Тип ценности, но kindOfX е константа, чиято стойност е конкретният вид х, низ.

Ето защо има краен брой видове като вътр, низ, плавам, масиви т.н., но безкраен брой типове, тъй като може да има няколко дефинирани от потребителя типа.

Ан интерфейс{} и а отразявам. Стойност работи почти по същия начин, те могат да съдържат стойности от всякакъв тип.

Разликата между тях се състои в това как е празен интерфейс{} никога не излага собствените операции и методи на стойността, която притежава. Така че повечето пъти трябва да знаете динамичния тип на стойността и да използвате утвърждение за тип за достъп до нея (т.е. i.(низ), x.(int)и т.н.), преди да можете да извършвате операции с него.

За разлика от това, a отразявам. Стойност има методи, които можете да използвате, за да изследвате неговото съдържание и свойства, независимо от неговия тип. Следващият раздел разглежда практически тези два типа и показва как са полезни в програмите.

Внедряване на отражение в Go програми

Отражението е много широко и може да намери приложение в програма по всяко време. По-долу са някои практически примери, които демонстрират използването на отражение в програми:

  • Проверете дълбокото равенство: The отразявам пакетът осигурява DeepEqual функция за проверка на стойностите на два обекта в дълбочина за равенство. Например две структури са дълбоко равни, ако всичките им съответстващи полета имат еднакви типове и стойности. Ето примерен код:
     // deep equality of two arrays
     arr1 := [...]int{1, 2, 3}
     arr2 := [...]int{1, 2, 3}
     fmt.Println(reflect.DeepEqual(arr1, arr2)) // true
  • Копирайте срезове и масиви: Можете също да използвате API за отражение на Go, за да копирате съдържанието на един срез или масив в друг. Ето как:
     slice1 := []int{1, 2, 3}
     slice2 := []int{4, 5, 6}
     reflect.Copy(reflect.ValueOf(slice1), reflect.ValueOf(slice2))
     fmt.Println(slice1) // [4 5 6]
  • Дефиниране на генерични функции: Езици като TypeScript предоставят общ тип, всякакви, който можете да използвате за съхранение на променливи от всякакъв тип. Въпреки че Go не идва с вграден общ тип, можете да използвате отражение, за да дефинирате общи функции. Например:
     // print the type of any value
     funcprintType(x reflect.Value) {
    fmt.Println("Value type:", x.Type())
     }
  • Достъп до структурни тагове: Таговете се използват за добавяне на метаданни към полетата на Go struct и много библиотеки ги използват, за да определят и манипулират поведението на всяко поле. Можете да получите достъп до структурни тагове само с отражение. Следният примерен код демонстрира това:
     type User struct {
    Name string`json:"name" required:"true"`
     }

     user := User{"John"}
     field, ok := reflect.TypeOf(user).Elem().FieldByName("Name")

     if !ok {
    fmt.Println("Field not found")
     }

     // print all tags, and value of "required"
     fmt.Println(field.Tag, field.Tag.Get("required"))
     // json:"name" required:"true" true

  • Отразяване на интерфейсите: Възможно е също така да се провери дали стойността имплементира интерфейс. Това може да бъде полезно, когато трябва да извършите допълнителен слой валидации въз основа на изискванията и целите на вашето приложение. Кодът по-долу демонстрира как отражението ви помага да проверявате интерфейсите и да определяте техните свойства:
     var i interface{} = 3.142
     typeOfI := reflect.TypeOf(i)
     stringerInterfaceType := reflect.TypeOf(new(fmt.Stringer))

     // check if i implements the stringer interface
     impl := typeOfI.Implements(stringerInterfaceType.Elem())
     fmt.Println(impl) // false

Горните примери са някои от начините, по които можете да използвате отражение във вашите реални Go програми. The отразявам пакетът е много здрав и можете да научите повече за възможностите му в официалния Отидете да размишлявате документация.

Кога да използвате размисъл и препоръчителни практики

Може да има множество сценарии, при които отражението може да изглежда идеално, но е важно да се отбележи, че отражението има свои собствени компромиси и може да повлияе негативно на програма, когато не се използва правилно.

Ето някои неща, които трябва да отбележите относно отражението:

  • Трябва да използвате отражение само когато не можете да определите предварително типа на обект във вашата програма.
  • Отражението може да намали производителността на вашето приложение, така че трябва да избягвате да го използвате за критични за производителността операции.
  • Отражението може да повлияе и на четливостта на вашия код, така че искате да избегнете да го хвърляте навсякъде.
  • С отразяването грешките не се улавят по време на компилиране, така че може да изложите приложението си на повече грешки по време на изпълнение.

Използвайте отражение, когато е необходимо

Reflection се предлага на много езици, включително C# и JavaScript, а Go се справя добре с отличното внедряване на API. Основно предимство на отразяването в Go е, че можете да решавате проблеми с по-малко код, когато използвате възможностите на библиотеката.

Безопасността на типа обаче е от решаващо значение за осигуряване на надежден код, а скоростта е друг важен фактор за безпроблемното потребителско изживяване. Ето защо трябва да използвате размисъл само след като претеглите възможностите си. И се стремете да поддържате кода си четим и оптимален.