Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 1695 сообщений
Cообщения с меткой

рефлексия - Самое интересное в блогах

Следующие 30  »
Solo-dance

ДВИГАЯСЬ ИЗ ПУСТОТЫ. (ПРОЖИТЬ ГОРЕ)

Среда, 27 Июля 2016 г. 18:07 (ссылка)

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

Ты не чувствуешь боли физической, ты не чувствуешь вкус пищи, ты не чувствуешь себя. Твоё существование сводится к самым простым действиям и потребностям.
Ты по-прежнему дышишь. Но уже не глубоко, не часто. Иногда забываешь дышать.
Ты через усилие принимаешь пищу. И сразу же забываешь, какую еду ты кушал.
Ты можешь забыть привести себя в порядок.
Бессменно носишь одну и ту же одежду. Практически никуда не выходишь.
Ты не хочешь общаться, не хочешь никому звонить. Но очень хочешь, чтобы позвонили тебе, поговорили с тобой, выслушали тебя.
Ты хочешь самого простого телесного контакта, прикосновений и объятия - поддерживающих, оберегающих и напоминающих тебе о том, что ты остался не один в этой огромной Вселенной.
И ты чувствуешь, как эта пустота заполняется болью. Душевной болью. С горячими непрекращающимися слезами, с аффективным и чувствами, с воспоминаниями, выскакивающими откуда-то из закоулков памяти, обжигающими и по-прежнему ранящими душу.
Через какое-то время боль души становится болью тела. И ты ощущаешь, как просыпается болью и другие истории - незавершённые, подавленные, забытые. Они откликаются сочувствие к новой боли. Иногда все вести, иногда по очереди.

Потребность продышать все проснувшиеся болью истории. Приложить ладонь, поговорить с ними, разглядеть теплом рук, обнять вниманием и любовью.
И Hans Zimmer (спасибо его музыке) выводит из пустоты.
Что происходит, когда я отказываюсь в пустоте? Ощущение, что она заполняет меня всю. Что не я в ней а она во мне. Что вынули душу. Что все внимание, силы ушли за тем, что совсем недавно было на месте нынешней пустоты.
Не сказать, не рассказать, не высказать.
Только вЫкричать и вЫплакать.

Хочу заполнить образовавшуюся пустоту не снаружи, не внешними объектами, а изнутри самой себя. И никто, ничто внешнее её не заполнит, только я сама. И выбор того, чем я её заполню, остаётся за мной.

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Solo-dance

ПРО ДВЕРИ И ФОРТОЧКИ.

Среда, 27 Июля 2016 г. 16:50 (ссылка)


«ЕСЛИ БОГ ЗАКРЫВАЕТ ПЕРЕД ТОБОЙ ДВЕРЬ, ТО ОН ОСТАВЛЯЕТ ОТКРЫТОЙ ФОРТОЧКУ».

Читаю сейчас эту фразу и два вопроса у меня возникают.

1. Как сделать так, чтобы перестать лазать по форточкам?

2. Как реагировать на фразы типа «стучи-откроют», «не ломись в открытую дверь», «эта дверь открывается в другую сторону», «это не твоя дверь»?

В первый раз фраза про закрытую дверь и открытую ФОРТОЧКУ звучит очень ободряюще, позитивно, ощущается невидимая поддержка.

Но когда каждый день и в течение долгого времени оторопело застывать перед закрывающейся дверью, потом искать ФОРТОЧКУ, а затем лезть в неё - как-то уже не радует. Злость с безнадёгой накрывают.



Вспоминаю одно упражнение с образом двери - необходимо было внутри себя увидеть дверь и войти в неё. Упражнение закончилось. Открываю глаза и у меня начинается смех - двери я не нашла. Было бескрайнее открытое пространство, посреди которого стояла одна дверная рама, ничем и никем не поддерживаемая. Двери нет, искать её не нужно, и открывать тоже. И, тем более, искать ФОРТОЧКУ и лезть в неё.

И реагировать на фразы о дверях можно нейтрально.





И как обычно, задашь вопрос и сам на него ответишь. Приятно иметь дело с «умным всезнающим собеседником».


Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Solo-dance

ПОКА ТИГРЫ В ПОЛУДРЁМЕ ПЕРЕВАРИВАЛИ МЯСО, КОРОВЫ ЯРОСТНО ПЛЕВАЛИ НИХ ПЕРЕЖЁВАННЫМ СЕНОМ

Вторник, 26 Июля 2016 г. 17:04 (ссылка)

Заглянув на один из форумов о вегетарианских блюдах, прочла несколько комментариев начинающих (просите) вегетарианцев типа «трупятина», «трупоедство» с явным пренебрежение к тем, кто использует в пище мясные блюда, рыбу, белки животного происхождения.
«Вегетарианцы» сваливали в кучу всё подряд, отстаивая свою позицию. И делали это с таким напором, что не вегетарианцы на этом форуме, пытавшиеся мягко прояснить свой взгляд на тему, чувствовали себя виноватыми и вынужденно оправдывались.
Ярое вегетарианство столкнулись с мягкостью мясоедов.
Для меня на поверхности обсуждения появлялось неуважение и нетерпимость к выбору другого человека, его потребностям, привычками, признание своей «вегетарианской» позиции как более гуманной, следовательно более духовно просвещённой и более высокой по уровню и , следовательно, дающей право возвышаться над другими и пренебрежительно навешивать ярлыки, манипулируя приёмом обобщения (если ешь мясо, значит агрессивный; если не можешь бросить пить и курить, значит лазер, слабак, маргинал).

Пока читала эту словесную перепалку, представила себе тех, кто живёт в районах северных широт, кочует вместе со садами оленей. У них-то точно травы, овощей и фруктов- завались! Оленевод-вегетарианец.
Легко бравировать вегетарианством, если у тебя есть возможности и условия для него. Легко быть вегетарианцем в тёплых краях.
Попробуй им остаться на берегу северных морей.
Попробуй им остаться, если у тебя сегодня на ужин только объедки и далеко не вегетарианские. И ты не наешь, когда тебе в следующий раз передаёт хотя бы это.
Попробуй им остаться, если тебе, для того, чтобы прокормить близких, гораздо выгодной купить мясо, чем килограмм помидор за ту же цену.
И всем ли вегетарианцы до конца последовательны в своей гуманности? Я имею в виду отказ от ношения одежды из меха и кожи? Вегетарианка в норковой шубе.
Любую тему можно довести до абсурда и фарса. И есть, действительно, настоящие, последовательные, убеждённые Вегетарианцы. Они не кичатся своим образом жизни. Они его выбрали не для того, чтобы выпендриться, а потому, что им так нравится, им это подходит.
Есть другие. Которые используют вегетарианство, чтобы быть особенным, и используя свою «особенность», выражать неуважение, презрение и отвращение к другому человеку. Чтобы потоптаться по его выбору, его праву на выбор. И вовсе не вегетарианство для них важно, а потребность выразить своё «фи» и возвыситься, унижая другого. А инструментом и средством может быть что угодно. Даже вегетарианство.

Метки:   Комментарии (1)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Рефлексивное метапрограммирование на Go: цикл for each средствами пакета reflect

Воскресенье, 24 Июля 2016 г. 20:41 (ссылка)

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



Конечно в Go нельзя писать обобщенные программы, например в стиле C++ templates, которые бы практически не влияли на затраты процессорного времени. Такого механизма в языке нет и, вполне возможно, что не предвидится.



С другой стороны, язык представляет довольно мощный встроенный пакет reflect, которой позволяет производить рефлексию как объектов, так и функций. Если не ставить быстродействие во главу угла, то с помощью этого пакета можно достигать интересных и гибких решений.



В этой статье я покажу как реализовать for each в виде типонезависимой рефлексивной функции.





Проблема



В языке Go для перебора элементов коллекции (Array, Slice, String) используется конструкция for range:



for i, item := range items {
// do something
}


Аналогичным образом можно выбрать элементы из Channel:



for item := range queue {
// do something
}


В общем-то это перекрывает 80% потребностей в цикле for each. Но у встроенной конструкции for range есть подводные камни, которые легко продемонстрировать на небольшом примере.



Допустим мы имеем две структуры Car и Bike (представим что пишем код для автомобильного магазина):



type Car struct{
Name string
Count uint
Price float64
}

type Bike struct{
Name string
Count uint
Price float64
}


Нам нужно подсчитать стоимость всех автомобилей и мотоциклов которые у нас есть в наличии.

Что бы это можно было сделать одним циклом в Go требуется новый тип, который обобщает доступ к полям:



type Vehicle interface{
GetCount() uint
GetPrice() float64
}

func (c Car) GetCount() uint { return c.Count; }
func (c Car) GetPrice() float64 { return c.Price; }
func (b Bike) GetCount() uint { return b.Count; }
func (b Bike) GetPrice() float64 { return b.Price; }


Теперь суммарную стоимость можно подсчитать организуя обход vehicles с помощью for range:



vehicles := []Vehicle{
Car{"Banshee ", 1, 10000},
Car{"Enforcer ", 3, 15000},
Car{"Firetruck", 4, 20000},
Bike{"Sanchez", 2, 5000},
Bike{"Freeway", 2, 5000},
}

total := float64(0)

for _, vehicle := range vehicles {
total += float64(vehicle.GetCount()) * vehicle.GetPrice()
}

fmt.Println("total", total)
// $ total 155000


Что бы не писать цикл каждый раз мы можем написать функцию которая принимает на вход тип []Vehicle и возвращает численный результат:



func GetTotalPrice(vehicles []Vehicle) float64 {
var total float64

for _, vehicle := range vehicles {
total += float64(vehicle.GetCount()) * vehicle.GetPrice()
}

return total
}


Выделяя этот код в отдельную функциюю, как ни странно, мы теряем в гибкости, т.к. появляется следующие проблемы:




  • Ограничение строгой типизации элементов. Т.к. конструкция for/range строго типизирована и не производит приведение типов элементов, то приходится явно указывать ожидаемый тип элементов в сигнатуре функции. Как следствие нет возможности передать срез []Car или []Bike напрямую, хотя оба типа — и Car, и Bike, удовлетворяют условиям интерфейса Vehicle:



cars := []Car{
Car{"Banshee ", 1, 10000},
Car{"Enforcer ", 3, 15000},
Car{"Firetruck", 4, 20000},
}

fmt.Println("total", GetTotalPrice(cars))
// Compilation error: cannot use cars (type []Car) as type []Vehicle in argument to GetTotalPrice



  • Ограничение строгой типизации коллекции. Например, нет возмоности передать вместо среза []Vehicle словарь map[int]Vehicle:



cars := map[int]Vehicle{
1: Car{"Banshee ", 1, 10000},
2: Car{"Enforcer ", 3, 15000},
3: Car{"Firetruck", 4, 20000},
}

fmt.Println("total", GetTotalPrice(cars))
// Compilation error: cannot use vehicles (type map[int]Vehicle) as type []Vehicle in argument to GetTotalPrice


Другими словами, for/range не позволяет выбрать произвольную часть кода и обернуть её в функцию не теряя гибкости.



Решение



Описанная проблема во многих языках со строгой типизацией решается привлечением механизма параметрического полиморфизма (generics, templates). Но взамен параметрического полиформизма авторы Go представили встроенный пакет reflect реализующий механизм рефлексии.

С одной стороны рефлексия является более затратным по ресурсам решением, но с другой, она позволяет создавать более гибкие и интеллектуальные алгоритмы.



Рефлексия типа (reflect.Type)



По сути в пакете reflect существует два вида рефлексии — это рефлексия типа reflect.Type и рефлексия значения reflect.Value. Рефлексия типа описывает исключительно свойства типа, поэтому две разные переменные с одним типом будут иметь одну и ту же рефлексию типа.



var i, j int
var k float32

fmt.Println(reflect.TypeOf(i) == reflect.TypeOf(j)) // true
fmt.Println(reflect.TypeOf(i) == reflect.TypeOf(k)) // false


Т.к. в Go типы конструируются на основе базовых типов, то для классификации существует специальное перечисление с типом Kind:



const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)


Таким образом, имея доступ к рефлексии типа reflect.Type, можно всегда узнать род типа, который позволяет произвести диспетчеризацию без определения полного типа переменной. Например, достаточно знать что переменная является функцией, не вдаваясь в подробности какой конкретный тип имеет эта функция:



valueType := reflect.TypeOf(value)
switch valuteType.Kind() {
case reflect.Func:
fmt.Println("It's a function")
default:
fmt.Println("It's something else")
}


Для удобства записи будем именовать рефлексию типа некоторой переменной тем же именем, но с суффиксом Type:



callbackType := reflect.TypeOf(callback)
collectionType := reflect.TypeOf(collection)


Кроме рода к которому принадлежит тип, с помощью рефлексии типа можно узнать остальную статическую информацию о типе (т.е. ту информацию которая не меняется во время выполнения). Например, можно узнать количество аргументов функции и тип ожидаемого аргумента на некоторой позиции:



if callbackType.NumIn() > 0 {
keyType := callbackType.In(0) // expected argument type at zeroth position
}


Аналогичным образом можно получить доступ к описанию членов структуры:



type Person struct{
Name string
Email string
}

structType := reflect.TypeOf(Person{})

fmt.Println(structType.Field(0).Name) // Name
fmt.Println(structType.Field(1).Name) // Email


Размер массива так же можно узнать через рефлексию типа:



array := [3]int{1, 2, 3}
arrayType := reflect.TypeOf(slice)

fmt.Println(arrayType.Len()) // 3


Но размер среза через рефлексию типа уже узнать нельзя, т.к. эта информация меняется во время выполнения.



slice := []int{1, 2, 3}
sliceType := reflect.TypeOf(slice)

fmt.Println(sliceType.Len()) // panic!


Рефлексия значения (reflect.Value)



Аналогично рефлексии типа, в Go существует рефлексия значения reflect.Value, которая отражает свойства конкретного значения хранящегося в переменной. Может показаться, что это довольно тривиальная рефлексия, но т.к. в Go переменная с типом interface{} может хранить всё что угодно — функцию, число, структуру и т.д., то и рефлексия значения вынуждена представлять в более–менее безопасном виде доступ ко всем вероятным возможностям объекта. Что, конечно же, порождает довольно длинный список методов.



Например, рефлексия функции может использоваться для вызова — достаточно передать список аргументов приведённый к типу reflect.Value:



 _callback := reflect.ValueOf(callback)
_callback.Call([]reflect.Value{ values })


Рефлексию коллекции (среза, массива, строки и т.д.) можно использовать для доступа к элементам:



_collection := reflect.ValueOf(collection)

for i := 0; i < _collection.Len(); i++ {
fmt.Println(_collection.Index(i))
}


Аналогичным образом работает рефлексия словаря — для обхода нужно получить список ключей через метод MapKeys и выбрать элементы через MapIndex:



for _, k := range _collection.MapKeys() {
keyValueCallback(k, _collection.MapIndex(k))
}


С помощью рефлексии структуры можно получить значения членов. При этом названия и типы членов следует получать из рефлексии типа структуры:



_struct := reflect.ValueOf(aStructIstance)

for i := 0; i < _struct.NumField(); i++ {
name := structType.Field(i).Name
fmt.Println(name, _struct.Field(i))
}


Рефлексивный цикл for each



Итак, если вернуться к for each, то желательно получить функцию которая принимала бы коллекцию и функцию обратного вызова произвольного типа, таким образом ответственность за согласование типов лежала бы на пользователе.



Т.к. единственная возможность в Go передать произвольный тип функции это указать тип interface{}, то в теле функции необходимо произвести проверки на основе информация содержащейся в рефлексии типа callbackType:




  • убедиться что функция обратного вызова действительно является функцией (через метод calbackType.Kind())

  • выяснить количество ожидаемых аргументов (метод callbackType.NumIn())

  • в случае провала вызвать panic()



В итоге получается примерно такой код:



func ForEach(collection, callback interface{}) {
callbackType := reflect.TypeOf(callback)
_callback := reflect.ValueOf(callback)

if callbackType.Kind() != reflect.Func {
panic("foreach: the second argument should be a function")
}

switch callbackType.NumIn() {
case 1:
// Callback expects only value
case 2:
// Callback expects key-value pair
default:
panic("foreach: the function should have 1 or 2 input arguments")
}
}


Теперь требуется спроектировать вспомогательную функцию которая будет производить обход по коллекции.

В неё удобнее передавать обратный вызов не в бестиповом виде, а в виде функции с двумя аргументами принимающую рефлексии ключа и элемента:



func eachKeyValue(collection interface{}, keyValueCallback func(k, v reflect.Value)) {
_collection := reflect.ValueOf(collection)
collectionType := reflect.TypeOf(collection)

switch collectionType.Kind() {
// loops
}
}


Т.к. алгоритм прохода коллекциии зависит от рода который можно получить через метод Kind() рефлексии типа, то для диспетчеризации удобно воспользоваться конструкцией switch-case:



switch collectionType.Kind() {
case reflect.Array: fallthrough
case reflect.Slice: fallthrough
case reflect.String:
for i := 0; i < _collection.Len(); i++ {
keyValueCallback(reflect.ValueOf(i), _collection.Index(i))
}
case reflect.Map:
for _, k := range _collection.MapKeys() {
keyValueCallback(k, _collection.MapIndex(k))
}
case reflect.Chan:
i := 0
for {
elementValue, ok := _collection.Recv()
if !ok {
break
}
keyValueCallback(reflect.ValueOf(i), elementValue)
i += 1
}
case reflect.Struct:
for i := 0; i < _collection.NumField(); i++ {
name := collectionType.Field(i).Name
keyValueCallback(reflect.ValueOf(name), _collection.Field(i))
}
default:
keyValueCallback(reflect.ValueOf(nil), _collection)
}


Как видно из кода, обход массива, среза и строки происходит одинаково. Словарь, канал и структура имеют свой собственный алгоритм обхода. В случае, если род коллекции не подпадает ни под один из перечисленных, алгоритм пытается передать в обратный вызов саму коллекцию, прим этом в качестве ключа указывается рефлексия указателя nil (которая на вызов метод IsValid() возвращает false).



Теперь, имея функцию производяющую беcтиповый обход коллекции, можно адаптирвоать её к вызову из функции ForEach обернув в замыкание. Это и есть окончательное решение:



func ForEach(collection, callback interface{}) {
callbackType := reflect.TypeOf(callback)
_callback := reflect.ValueOf(callback)

if callbackType.Kind() != reflect.Func {
panic("foreach: the second argument should be a function")
}

switch callbackType.NumIn() {
case 1:
eachKeyValue(collection, func(_key, _value reflect.Value){
_callback.Call([]reflect.Value{ _value })
})
case 2:
keyType := callbackType.In(0)
eachKeyValue(collection, func(_key, _value reflect.Value){
if !_key.IsValid() {
_callback.Call([]reflect.Value{reflect.Zero(keyType), _value })
return
}

_callback.Call([]reflect.Value{ _key, _value })
})
default:
panic("foreach: the function should have 1 or 2 input arguments")
}
}


Надо заметить, что в случае когда функция обратного вызова ожидает передачу двух аргументов (пары ключ/значение) необходимо производить проверку корректности ключа, т.к. он может оказаться невалидным. В последнем случае на основе типа ключа конструируется нулевой объект.



Примеры



Теперь пришло время продемонстироровать что же даёт наш подход. Если вернуться к проблеме, мы теперь можем решить её таким путём:



func GetTotalPrice(vehicles interface{}) float64 {
var total float64

ForEach(vehicles, func(vehicle Vehicle) {
total += float64(vehicle.GetCount()) * vehicle.GetPrice()
})

return total
}


Эта функция, в отличии от приведённой в начале статьи, гораздо гибче, т.к. позволяет подсчитывать сумму вне зависимости от типа коллекции и не обязывает приводить тип элементов к интерфейсу Vehicle:



vehicles := []Vehicle{
Car{"Banshee ", 1, 10000},
Bike{"Sanchez", 2, 5000},
}

cars := []Car{
Car{"Enforcer ", 3, 15000},
Car{"Firetruck", 4, 20000},
}

vehicleMap := map[int]Vehicle{
1: Car{"Banshee ", 1, 10000},
2: Bike{"Sanchez", 2, 5000},
}

vehicleQueue := make(chan Vehicle, 2)
vehicleQueue <- Car{"Banshee ", 1, 10000}
vehicleQueue <- Bike{"Sanchez", 2, 5000}
close(vehicleQueue)

garage := struct{
MyCar Car
MyBike Bike
}{
Car{"Banshee ", 1, 10000},
Bike{"Sanchez", 1, 5000},
}

fmt.Println(GetTotalPrice(vehicles)) // 20000
fmt.Println(GetTotalPrice(cars)) // 125000
fmt.Println(GetTotalPrice(vehicleMap)) // 20000
fmt.Println(GetTotalPrice(vehicleQueue)) // 20000
fmt.Println(GetTotalPrice(garage)) // 15000


И небольшой бенчмарк для двух идентичных циклов, который наглядно показывает за счёт чего достигается гибкость:



// BenchmarkForEachVehicles1M
total := 0.0
for _, v := range vehicles {
total += v.GetPrice()
}


//BenchmarkForRangeVehicles1M
total := 0.0
ForEach(vehicles, func(v Vehicle) {
total += v.GetPrice()
})


PASS
BenchmarkForEachVehicles1M-2 2000000000 0.20 ns/op
BenchmarkForRangeVehicles1M-2 2000000000 0.01 ns/op


Заключение



Да, в Go нет параметрического полиформизма. Но зато есть пакет reflect, который предоставляет обширные возможности в области метапрограммирования. Код с использованием reflect конечно же выглядит намного сложнее, чем типичный код на Go. С другой стороны, рефлексивные функции позволяют создавать более гибкие решения. Это очень важно при написании прикладных библиотек, например, при реализации концепции Active Record.



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



github Исходный код на github


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/306304/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<рефлексия - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda