Страницы

Поиск по вопросам

понедельник, 30 декабря 2019 г.

Чем отличается мост от коммутатора?

#сеть #потоки_данных #администрирование #маршрутизация #пакет


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


Правильно ли я понимаю, что коммутатор - это устройство с
несколькими портами, которое в отличие от концентратора может
передавать сигнал на конкретный порт (концентратор может только
повторять на все порты) благодаря таблице маршрутизации?  
Тогда не пойму
как у коммутатора происходит обучение (таблица маршрутизации), ведь
пока на каждый из портов не будут отправлены данные, таблица полностью
не заполнится? Это значит, что пока таблица не заполнится, все
компьютеры сети смогут видеть, что я хотел передать только одному
конкретному компьютеру (это вроде как небезопасно)? 
Правильно ли я
понимаю, что концентратор работает как аналоговое устройство -
сигнал который передали он повторил и все? А коммутатор же как
цифро-аналоговое - он сначала цифровым образом разбил на пакеты инфу,
а потом уже по аналогу (кабелю) отправил в нужный порт (или во все порты, если идет
обучение)?
Чем мост отличается от коммутатора?

    


Ответы

Ответ 1



Да. Только это не совсем таблица маршрутизации; Почитайте как работает протокол ARP; Да. Примерно так Они соединяют сети на разных уровнях. Мост - более сложная железка - может сделать одну IP сеть с единым адресным пространством из разных сетей (в том числе удаленных друг от друга) Мост соединяет сети на втором уровне. Но трафик между "концами" моста может идти через любые уровни. Мост анализирует сеть и собирает таблицу MACов отмечая какой физической сети они принадлежат. Получая пакет анализирует адрес получателя. Если этот адрес не принадлежит сети из которой пришел пакет мост передает его в другой интерфейс. Если получатель и отправитель находятся в одной сети мост игнорирует пакет. В современных сетях, наверное, самое распространенное применение в Wi-Fi точках доступа.

Ответ 2



Коммутатор работает на втором уровне модели OSI ( подуровень MAC ), так как анализирует МАС-адреса внутри пакета 10( рис. .). Естественно, он выполняет и функции первого уровня. Маршрутизаторы работают на третьем уровне модели OSI, так как они анализируют не только MAC-адреса пакета, но и IP-адреса, то есть более глубоко проникают в инкапсулированный пакет Задача сегментации сети, т.е. разделения пользователей на группы (сегменты) в соответствии с их физическим размещением с целью уменьшения количества клиентов, соперничающих за полосу пропускания, была решена с помощью устройства, называемого мостом (bridge). Мост был разработан компанией Digital Equipment Corporation (DEC) в начале 1980-х годов и представлял собой устройство канального уровня модели OSI (обычно двухпортовое), предназначенное для объединения сегментов сети. В отличие от концентратора, мост не просто пересылал пакеты данных из одного сегмента в другой, а анализировал и передавал их только в том случае, если такая передача действительно была необходима, то есть адрес рабочей станции назначения принадлежал другому сегменту. Таким образом, мост изолировал трафик одного сегмента от трафика другого, уменьшая домен коллизий и повышая общую производительность сети. Однако мосты были эффективны лишь до тех пор, пока количество рабочих станций в сегменте оставалось относительно невелико. Как только оно увеличивалось, в сетях возникала перегрузка (переполнение приемных буферов сетевых устройств), которая приводила к потере пакетов. Увеличение количества устройств, объединяемых в сети, повышение мощности процессоров рабочих станций, появление мультимедийных приложений и приложений "клиент-сервер" требовали большей полосы пропускания. В ответ на эти растущие требования фирмой Kalpana в 1990 г. на рынок был выпущен первый коммутатор (switch), получивший название EtherSwitch. Коммутатор локальной сети Коммутатор представлял собой многопортовый мост и также функционировал на канальном уровне модели OSI. Основное отличие коммутатора от моста заключалось в том, что он мог устанавливать одновременно несколько соединений между разными парами портов. При передаче пакета через коммутатор в нем создавался отдельный виртуальный (либо реальный, в зависимости от архитектуры) канал, по которому данные пересылались напрямую от порта-источника к порту-получателю с максимально возможной для используемой технологии скоростью. Такой принцип работы получил название "микросегментация". Благодаря микросегментации коммутаторы получили возможность функционировать в режиме полного дуплекса (full duplex), что позволяло каждой рабочей станции одновременно передавать и принимать данные, используя всю полосу пропускания в обоих направлениях. Рабочей станции не приходилось конкурировать за полосу пропускания с другими устройствами, в результате чего не происходили коллизии и повышалась производительность сети.

Почему в первом коде не нужен нулевой символ?

#cpp


У нас есть функция которая принимает две строки и производит слияние

void strcat(char *to, const char *from)
{
    while (*to) to++;
    while (*to++ = *from++);
}


Почему здесь не требуется добавить нулевой символ в отличие например от такого кода

void strcat(char *to, const char *from)
{
    while (*to != '\0') {
        to++;
    }

    while (*from != '\0') {
        *to = *from;
        from++;
        to++;
    }
    *to = '\0';
}

    


Ответы

Ответ 1



Нулевой символ здесь добавляется автоматом. Выражение *to++ = *from++ выполняет присвоение, после чего возвращает новое значение *to. То есть, сначала ноль скопируется из *from в *to, а уж потом он будет проанализирован в while, который прекратится.

переменная errno в многопоточной программе

#c #posix


здравствуйте, допустим, в нескольких программных нитях(потоках) вызываем функцию
read... и она завершается в одном из нитей, допустим, с errno = EAGAIN, в другой с
errno = EBADF... потокобезопасна ли переменная errno, или в каждой нити она своя? 
    


Ответы

Ответ 1



Короткий ответ -- да, errno потокобезопасна. Это требование Posix. (смотри этот ответ)

Ответ 2



Смотрим man errno: errno is thread-local; setting it in one thread does not affect its value in any other thread.

mysqli вывод по одной записи

#php #mysql


Добрый день. Есть база такого формата

Структура: 
id - цифры (идут не всегда по порядку)
text - mediumtext (тут какая то цитата)


Задача в том, чтобы выводить их по очереди по 1 записи. А точнее при нажатии кнопки
"Следующая" должна вывестись следующая запись с базы данных. Так как id не всегда по
порядку, то столкнулся с проблемой реализации, так как с БД еще мало знаком. 
    


Ответы

Ответ 1



Вам стоит прочитать про это http://postgresql.ru.net/manual/queries-limit.html $sql = 'SELECT `id`, `text` FROM `comments` WHERE 1 LIMIT 1 OFFSET.$page; Вообще советую не пилить велосипед и использовать Doctrine http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html Так как запросы в php весьма сложны в обслуживании.

Ответ 2



Не обязательно делать выборку по id. Записи в БД хранятся в порядке добавления и этим порядком можно воспользоваться. Предположим что таблица называется comments, тогда использует такой запрос: SELECT `id`, `text` FROM `comments` WHERE 1 LIMIT 0, 1 Ключевое здесь - LIMIT 0, 1 где 1 - это кол-во строк, а 0 - отступ. Если изменить на LIMIT 2, 1, то мы получим только 3 строку из таблицы. LIMIT работает уже после WHERE, ORDER BY и GROUP BY

Как распарсить объект такого вида на c#?

#c_sharp #json #jsonnet


var tree = {
   left: {
       left: "Первое предложение из произвольной строки",
       right: {
           left: "Другое произвольное предложение",
           right: "Еще одно следующее предложение, но не очень длинное"
       }
   },
   right: {
       left: {
           left: {
               left: "Еще одно не очень длинное предложение",
               right: ""
           }, 
           right: {
               left: "",
               right: "Еще одно не очень длинное предложение"
           }
       },
       right: {
           left: {
               left: "Предложение",
               right: "Еще одно следующее предложение, но не очень длинное"
           },
           right: {
               left: "Другое произвольное предложение",
               right: {
                   left: "Два слова",
                   right: "Еще одно следующее предложение, но не очень длинное"
               }
           }
       }
   }
}

    


Ответы

Ответ 1



Берем ваш JSON string json = @"{ left: { left: ""Первое предложение из произвольной строки"", right: { left: ""Другое произвольное предложение"", right: ""Еще одно следующее предложение, но не очень длинное"" } }, right: { left: { left: { left: ""Еще одно не очень длинное предложение"", right: """" }, right: { left: """", right: ""Еще одно не очень длинное предложение"" } }, right: { left: { left: ""Предложение"", right: ""Еще одно следующее предложение, но не очень длинное"" }, right: { left: ""Другое произвольное предложение"", right: { left: ""Два слова"", right: ""Еще одно следующее предложение, но не очень длинное"" } } } } }"; Генерируем классы для него тут http://json2csharp.com/ (также в студии можно использовать специальную вставку Paste Special. Для этого надо предвариетльно json скопировать в буфер обмена.) public class Right { public string left { get; set; } public string right { get; set; } } public class Left { public string left { get; set; } public Right right { get; set; } } public class Left3 { public string left { get; set; } public string right { get; set; } } public class Right3 { public string left { get; set; } public string right { get; set; } } public class Left2 { public Left3 left { get; set; } public Right3 right { get; set; } } public class Left4 { public string left { get; set; } public string right { get; set; } } public class Right6 { public string left { get; set; } public string right { get; set; } } public class Right5 { public string left { get; set; } public Right6 right { get; set; } } public class Right4 { public Left4 left { get; set; } public Right5 right { get; set; } } public class Right2 { public Left2 left { get; set; } public Right4 right { get; set; } } public class RootObject { public Left left { get; set; } public Right2 right { get; set; } } Для десериализации я использую библитеку https://www.newtonsoft.com/json - её можно скачать через nuget (https://www.nuget.org/packages/Newtonsoft.Json/). После подключения библиотеки, десериализуем JSON в объект var myObject = JsonConvert.DeserializeObject(json); Готово.

Не туда, куда надо добавляется класс

#jquery


Здравствуйте.

Я еще учу jQuery. Сегодня столкнулся с проблемой, что не туда, куда надо добавляется
класс. Нужно, чтобы новый класс был у 

, а вышло у . $(function () { var elem = $('body'); elem .append('

Some text

')) .addClass('new'); }); .new { color: red; } Заранее спасибо.


Ответы

Ответ 1



.prependTo( "body" ); вам в помощь или .appendTo("body"); $(function() { $('

') .html('Some text') .addClass('new') .prependTo("body"); }); .new { color: red; }

Ответ 2



//первый вариант: $(function() { var elem = $('body'); elem.append('

Some text

'); }); //второй вариант $(function() { var elem = $('body'); elem.append('

Some text

'); $('p').addClass('new'); });

Ответ 3



Цепочные вызовы jQuery основаны на том, что многие методы объекта-обертки возвращают себя. Таким образом, Вам надо добавлять элемент, используя метод правильного объекта - того, которому Вы хотите следующим вызовом добавить класс: var elem = $('body'); $('

').appendTo(elem).addClass('new');

заменить строки в одном текстовом файле информацией из второго

#python #bash #perl #cmd #shell


Именются 2 гигантских текстовых файла.

file1.txt (3,6 Гб) содержит только одну колонку (в том числе много дубликатов):

123456
123456
123456
абвгд
абвгд
01щенок
01щенок
01щенок
01щенок
01щенок
a0125uß
a0125uß


file2.txt (1,5 ГБ) содержит ту же колонку, но без дубликатов плюс вторую колонку.

123456:artur
абвгд:sergey
01щенок:max
a0125uß:stasik


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

artur
artur
artur
sergey
sergey
max
max
max
max
stasik
stasik


У меня есть такой код:

import io
STRFILE1 = 'file1.txt'
STRFILE2 = 'file2.txt'
STRFILERESULT = 'result.txt'
fIN = open(STRFILE1,'r')
strContent = fIN.read()
fIN.close()

with open(STRFILE2,'r') as f:
    for line in f:
        mapping = line.split(":",1)
        strContent = strContent.replace(mapping[0],mapping[1].rstrip("\n"))

fOUT = open(STRFILERESULT,'w')
fOUT.write(strContent)
fOUT.close()


но он работает вечно с таким объёмом строк (102.600.000 - файл 1 и 50.000.000 - файл
2). Как можно ускоритъ процесс обработки?
    


Ответы

Ответ 1



Если на python, то можно так: def story_key(): with open('te2', 'r') as f2: my_key = {i.split(':')[0]: i.split(':')[1].strip() for i in f2} return my_key all_key = story_key() def read_small(f_object, f_size=1024): while True: data = f_object.read(f_size) if not data: break yield data def f_write(): with open('te1') as f1: with open('te3', 'a') as f3: for i in read_small(f1): a = [all_key[j] + '\n' for j in i.split('\n') if j] f3.write(''.join(a)) f_write()

Ответ 2



Как можно ускоритъ процесс обработки? например, можно воспользоваться не языком программирования, а самыми обыкновенными gnu-утилитами join, sort, cut, nl. с большой долей вероятности это будет работать быстрее, нежели манипуляции со «словарями», или, тем более, базой данных (время на создание индекса, скорее всего, значительно превысит время, за которое отработают предлагаемые утилиты). если порядок строк не важен, то замена будет произведена довольно быстро: $ join -t : -o 2.2 <(sort файл1) <(sort файл2) max max max max max artur artur artur stasik stasik sergey sergey если порядок важен, вычислений понадобится значительно больше. что-нибудь в этом духе: $ join -t : -1 2 -o 1.1,2.2 <(nl -n rz -s ':' файл1 | sort -t ':' -k 2) <(sort файл2) | sort -n | cut -d : -f 2 artur artur artur sergey sergey max max max max max stasik stasik

Ответ 3



Ваш скрипт медленный потому что вы для каждого уникального значения создаёте 3.6GB строчку заново. Предполагая что все дубликаты подряд идут и порядок уникальных значений одинаковый в обоих файлах, можно читать файл с заменами и писать их в выходной файл столько раз, сколько текущий ключ повторяется в файле с дубликатами: #!/usr/bin/env python from itertools import groupby with open('file1.txt', 'rb') as dups_file, \ open('file2.txt', 'rb') as replacements_file, \ open('result.txt', 'wb') as output_file: groups = groupby(dups_file) for line in replacements_file: key, value = line.split(b':') dupe_key, dupes = next(groups) assert key == dupe_key.rstrip(), (key, dupe_key) for _ in dupes: output_file.write(value) Чтобы сделать код более устойчивым к неправильному вводу, в зависимости от вашей ситуации, добавьте try/except и пропускайте соответствующие строки. Для ожидаемого ввода, код как есть работает. Этот код читает по одной строчке из каждого файла за раз (минимально памяти требует O(1)). Использование 'b' режима предполагает, что текст в файлах закодирован используя одинаковые кодировки.

Ответ 4



Я не зря задавал вопрос про упорядоченность повторяющихся данных. Эту мысль подхватил @jfs и прислал практически оптимальное решение с учетом регулярности данных. Добавлю только, что основное время уходит на обработку строки: strContent = strContent.replace(mapping[0],mapping[1].rstrip("\n")) которую вы постоянно держите "в памяти". Чтобы было понятно - сколько примерно времени уходит на "ворочанье" в памяти strContent приведу близкий по смыслу код. Первый пример - почти как у вас - "все в одно": # -*- coding: utf-8 -*- from time import time fw = open('fileDict.txt',"w", buffering=4096, encoding='utf-8') out_text = '' prefix = "key" t_start = time() for i in range(10000000): out_text += prefix+str(i)+":" + str(i)+ '\n' fw.write(out_text) t_end = time() fw.close() print('work_time=', t_end - t_start ) # results: # without buffering in line #4 # 1 000 000 time 27.8 sec # 10 000 000 time 3403.8 sec # with buffering in line #4 # 1 000 000 time 26.8 sec # 10 000 000 time 3350.8 sec второй вариант - запхнем кусочками в список: from time import time fw = open('fileDict.txt',"w",encoding='utf-8') out_text = '' prefix = "key" out_list = [] t_start = time() for i in range(10000000): out_list.append( prefix+str(i)+":" + str(i)+ '\n' ) t_middle = time() for line in out_list: fw.write(line) t_end = time() fw.close() print('work_time=', t_end - t_start, "parsing time:", t_middle-t_start, \ " + writing_time: ", t_end - t_middle ) # results: # 1 000 000 time 2.2 sec # 10 000 000 time 21.8 sec печать для 1 000 000: work_time= 2.2221806049346924 parsing time: 1.2595593929290771 + writing_time: 0.9626212120056152 печать для 10 000 000: work_time= 21.796194791793823 parsing time: 12.18700361251831 + writing_time: 9.609191179275513 Из чего следует, что представление обрабатываемых данных вашим программистом было выбрано не лучшим образом. Действительно разница в обработке как 3340 к 12 ... на построении данных для файла в 10 млн строк размером почти 200Мб

Множественные ошибки вычислений с плавающей точкой

#cpp #c #double


Есть функция 

inline unsigned long long d(double d)
{
    return (864E9 * d + 0x014f35a9a90cc000 - 0x019DB1DED53E8000) / 10;
}


При ее работе вылетает такая ошибка(код 0xC00002B4)


  Множественные ошибки вычислений с плавающей точкой (parameters: 0x00000000, 0x000005A0).


Самое интересное что эта функция вызывается дважды с одним и тем же входным параметром.
И такая ошибка появляется при повторном вызове. Я пробовал сделать семпл в отдельном
проекте но воспроизвести ошибку не получилось.

Что эта ошибка вообще означает? и как это можно исправить?

PS. VisualStudio 2015

Настройки проекта(Code Generation)

Smaller Type Check: No
Basic Runtime Checks: Default
Runtime Library: /MDd
Floating Point Model: Precise (/fp:precise)


PS2. Если переписать функцию так:

inline unsigned long long GetTsFromDate(double date)
{
    unsigned long long tmp = 0x014f35a9a90cc000 - 0x019DB1DED53E8000;
    double dbl = 864E9 * date;
    double dbl2 = dbl + tmp;
    double result = dbl2 / 10;
    return result;
}


То будет падать на double dbl = 864E9 * date
    


Ответы

Ответ 1



Провёл несколько экспериментов в Visual Studio 2010. Создал консольное приложение с настройками по умолчанию (в частности, модель вычислений с плавающей точкой /fp:precise, исключения с плавающей точкой отключены /fp:except-). Все примеры выполнялись в Debug-режиме. Воспользуемся функцией _statusfp2 для того чтобы узнать floating-point status word в следующем простом примере: #include #include #include using namespace std; #pragma fenv_access (on) int main() { cout.precision(numeric_limits::max_digits10); unsigned int x86, SSE2; double d; _statusfp2(&x86, &SSE2); cout << x86 << " " << SSE2 << endl; d = 0.0; d = d * 1.0; _statusfp2(&x86, &SSE2); cout << d << endl; cout << x86 << " " << SSE2 << endl; return 0; } В моём случае, программа выдала следующий результат: 0 0 0 0 0 Насколько я понял, нулевые значения переменных x86 и SSE2 означают, что при вычислениях с плавающей точкой никаких исключительных ситуаций не произошло. Это логично, ибо никаких "опасных" вычислений в данном пример не осуществляется. Воспользуемся примером из вашего вопроса: d = 864E9; d = d * 43083.341116850243; _statusfp2(&x86, &SSE2); cout << d << endl; cout << x86 << " " << SSE2 << endl; В моем случае программа выдала следующий результат: 37224006724958608 1 0 В приведённом выводе программы есть два важных момента. Во-первых, результат перемножения двух чисел 864E9 и 43083.341116850243 получился не точным. Это легко проверить перемножением этих чисел на калькуляторе: точный результат содержит 20 значащих цифр. Такое число не может быть представлено в переменной типа double. Во-вторых, изменилось состояние floating-point status word. Судя по справке, status word приняло значение _EM_INEXACT. То есть имела место исключительная ситуация — результат арифметической операции не может быть точно представлен в переменной типа double. Тем не менее, программа завершила свою работу нормально, никакого исключения сгенерировано не было. Это обусловлено тем, что по-умолчанию исключения с плавающей точкой замаскированы. Воспользуемся функцией _controlfp_s для того, чтобы демаскировать исключение _EM_INEXACT: unsigned int currentControl _clearfp(); _controlfp_s(¤tControl, 0, 0); _controlfp_s(nullptr, currentControl & ~static_cast(_EM_INEXACT), _MCW_EM); d = 864E9; d = d * 43083.341116850243; В этот раз на строке d = d * 43083.341116850243; выскакивает ошибка: 0xC000008F: Floating-point inexact result. В настройках проекта включим расширенный набор инструкций /arch:SSE2 и на той же самой строке выскакивает немного другая ошибка: 0xC00002B4: Множественные ошибки вычислений с плавающей точкой. А это весьма похоже на ошибку в вашем вопросе. Полагаю, где-то в вашем проекте по какой-то причине демаскируются исключения с плавающей точкой, и обратная маскировка не производится. Помимо исключения _EM_INEXACT есть также исключения _EM_INVALID, _EM_DENORMAL, _EM_ZERODIVIDE, _EM_OVERFLOW и _EM_UNDERFLOW. Замаскировать их все можно следующим образом: _clearfp(); _controlfp_s(nullptr, _MCW_EM, _MCW_EM); P.S. При манипулировании floating-point status word прагма #pragma fenv_access (on) обязательна, иначе компилятор может проигнорировать манипуляции. Также, если всё-таки хочется обрабатывать исключения с плавающей точкой, то судя по всему необходимо использовать опцию /fp:except, иначе может что-нибудь сломаться. Но тут я не уверен.

Ответ 2



В вашей второй функции первая строка меня очень смущает. unsigned long long tmp = 0x014f35a9a90cc000 - 0x019DB1DED53E8000; Зачем вы присваиваете unsigned long число, которое заведомо меньше нуля? Тут даже видно, 0х014 - 0х019. И зачем вам long long, когда хватит обычного long? У меня при выполнении этого действия(отладка) tmp == 18424652457709551616 Далее, смотрю на первую функцию. Вижу что-то вроде переполнения. 864E9 * d + 0x014f35a9a90cc000 здесь вы к double результату 864E9 * d прибавляете 0x014f35a9a90cc000, а второе число уже длиннее пятнадцати значащих знаков double, вряд ли вы контролируете это переполнение. (у double после 15-го знака идут нули) Ну и далее, от сомнительного результата предыдущего действия вы отнимаете еще один long, значение которого опять же больше double. Вот вам и множественные ошибки вычислений. По умолчанию такие ошибки(исключения) скрыты, у вас, видимо, они включены.

Как можно выравнить числа в таблице по точке или запятой?

#css #html5 #табличная_верстка


Существует возможность средствами HTML+CSS выравнить в таблице, в теге TD числа по
определенному знаку (по точке или запятой)?
Например:

----
  153.12
   98.357
  753.00
    0.002
   15
32145.9998   

    


Ответы

Ответ 1



Делается разбиением данных на две части. А сортировка делается по атрибуту data. Плюсом этого решения является то что данные можно копировать через выделение. .start { display: inline-block; width:50px; text-align:right; }
123.01
1.122
22.1
12345.111


Ответ 2



Ну почти ))) Через data- атрибуты. div { position: relative; margin-left: 3em; } div::before { content: attr(data-before); text-align: right; width: 5em; position: absolute; left: -5em; } div::after { content: attr(data-after); position: absolute; }
.
.
.
.
 
.


Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager` from root provider

#c_sharp #aspnet_core #dependency_injection #aspnet_core_2


У меня есть сервис в проекте ASP.NET Core 2.0

public class SomeSingletonService: IUserGetPropertiesService
{
   private readonly IServiceProvider _serviceProvider;

   public SomeSingletonService(IServiceProvider serviceProvider)
   {
      _serviceProvider = serviceProvider;
   }

   public void SomeFunction() {
       // в этой строчке падает с ошибкой
       UserManager userManager = _serviceProvider.GetService>();
       // ...
   }
}


Сервис регистрируется как Singleton

services.AddSingleton();


При попытке получить UserManager из _serviceProvider падает с ошибкой


  {System.InvalidOperationException: Cannot resolve scoped service
  'Microsoft.AspNetCore.Identity.UserManager`1[MyProject.Models.User]'
  from root provider.


Не могу понять в чём дело, ведь в SomeFunction по идее можно получать scoped сервисы.
Как мне в SomeFunction прокинуть UserManager?

Не хочется ей передавать его в параметрах, так как тогда пришлось бы через всю логику
приложения носить этот UserManager, тогда как по идее можно его извлекать из
Dependance Injection Container, который я пробую передать через конструктор - IServiceProvider
serviceProvider
    


Ответы

Ответ 1



Выяснилось что Scoped сервисы нужно получать через специальный блок using (var serviceScope = _serviceProvider.GetRequiredService() .CreateScope()) { UserManager userManager = serviceScope.ServiceProvider.GetService>(); }

Ответ 2



Другое решение — отключить проверку областей видимости для сервисов, поставляемых средством DI. Это делается в Program.cs, найдите место создания IWebHostBuilder и добавьте: WebHost.CreateDefaultBuilder(args) .UseStartup() .UseDefaultServiceProvider(options => options.ValidateScopes = false); // <==

Суть конструктора по-умолчанию в наследовании

#c_sharp #net #наследование


Здравствуйте. Зачем когда мы создаем какой-нибудь конструктор в базовом классе, обязательно
надо создать еще и конструктор по-умолчанию, в противном случае не получается создавать
объект унаследованного класса. Например, если в этом коде попытаемся комментировать
конструктор по-умолчанию, выдается ошибка

using System;
class one
{
    private int ID;
    //public one() { }
    public one(int ID)
    {
        this.ID = ID;
    }
}
class two : one
{
    int age;string name, position;
    public two(int age, string name, string position)
    {
        this.age = age;
        this.name = name;
        this.position = position;
    }
    public void show()
    {
        Console.WriteLine(name + " " + position + " " + age);
    }
}
class consoleapp
{
    static void Main()
    {
        two obj = new two(25,"Shamil", "IT");
        obj.show();
        Console.ReadKey();
    }
}

    


Ответы

Ответ 1



На самом деле не обязательно. При конструировании объекта производного класса мы обязаны вызвать конструктор базового и если вы не указываете какой конкретно конструктор нужно вызвать, то компилятор по умолчанию ищет конструктор без параметров. Конкретно ваш код скомпилируется, если написать, например, так: public two(int age, string name, string position) : base(1)

Можно ли игнорировать пустого наследника при написании деструктора?

#cpp #наследование #language_lawyer #неопределенное_поведение


Как известно, при необходимости удаления через указатель на родительский класс, класс
должен иметь виртуальный деструктор, чтобы оператор delete вызвал верный деструктор
дочернего класса.

Меня же интересует случай, когда дочерний класс не добавляет к родительскому ничего,
что следовало бы уничтожать. Например, вообще не добавляет никаких полей к базовому
классу. Можно ли в таком случае проигнорировать правило виртуальности деструктора или
даже в таком случае удаление будет UB?

Пример кода: https://ideone.com/B3Wx7m

struct A {
  int *p;
  A(unsigned n) : p(new int[n]) {}
  ~A() { delete [] p; }
};

struct B : A
{
  B() : A(4) {}
};

int main()
{
  A *a = new B();
  delete a;

  return 0;
}

    


Ответы

Ответ 1



В стандарте четко сказано, что такое удаление вызывает неопределенное поведение. Не делается никаких оговорок на тему того, добавлены ли какие-то поля в класс-наследник или нет. 5.3.5 Delete 3 In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. [...] На деструктор класса также обычно накладываются (могут накладываться) какие-то неявные служебные функции, которые могут работать неправильно при вызове неправильного деструктора. В частности, в типичной реализации на деструктор возложена обязанность вызова правильной функции operator delete, которая может быть перегружена для каждого класса отдельно. То есть если бы в struct B была определена своя статическая функция operator delete, то без виртуального деструктора обеспечивать ее функциональность пришлось бы какими-то другими методами. (Авторы стандарта, скорее всего, и ориентировались именно на такую реализацию вызова перегруженного operator delete.) Например #include struct A { // virtual ~A() {} }; struct B : A { static void *operator new(size_t s) { return (char *) std::malloc(s * 2) + s; } static void operator delete(void *p, size_t s) { std::free((char *) p - s); } }; int main() { A* p = new B; delete p; } В популярных реализациях такой код упадет из-за вызова неправильного operator delete. Но достаточно добавить в A виртуальный деструктор, как все станет хорошо. Обратите внимание, что оба члена B - статические функции, то есть физически в B ничего не добавлено.

Указатели на функции

#c #указатели


Объясните, пожалуйста, есть ли разница между двумя записями, если есть, то какая? 

#include 

int sum(int a, int b){
    return a+b;
}

main(){

    int (*fun)(int , int) = NULL;
    fun = sum;

    printf("%d\n\n", fun(12,14));
    printf("%d\n\n",(*fun)(12,14));


   return 0;
}

    


Ответы

Ответ 1



Разница существует лишь на абстрактном концептуальном уровне. Фактической разницы нет. Получение адреса функции тоже можно записать как fun = sum; или как fun = ∑. Разницы тоже нет. Можно, разве что, посоветовать быть единообразным, т.е. либо использовать явные операторы и там, и там fun = ∑ (*fun)(12,14); либо не использовать их ни там, ни там fun = sum; fun(12,14); Хотя и этот совет, возможно, не заслуживает большого внимания.

Ответ 2



Разницы по сути нет никакой, но этот вопрос заслуживает отдельного внимания из-за своей истории. В первом случае (*fun)(), так как fun указывает на ф-цию sum, то *fun - это ни что иное как sum. Во втором случае, когда fun () - это можно объяснить тем, что функция и указатель на нее - взаимозаменяемы! Но вот почему так? Почему не использовать один из подходов? Дело в том, что язык Си бурно развивался еще до того, как был опубликован первый стандарт и к этому времени уже были использованы оба варианта разными командами разработчиков. В частности первый подход выбрали разработчики, которые расширяли Unix в Bell Labs, а второй - которые расширяли Unixв Беркли. Стандарт, в целях совместимости, разрешил использовать оба подхода как эквивалентные.

Python декораторы

#python #python_3x #декоратор


Каким образом функция func() передалась как аргумент в функцию deco() ?

ps = input("Введите пароль:")

def test_pass(p):
    def deco(f):
        if p == "universe":
            return f
        else:
            return lambda: "Access denied"
    return deco

@test_pass(ps)
def func():
    return "Access approval"

print(func())

    


Ответы

Ответ 1



Грубо говоря, Python разворачивает конструкцию @test_pass(ps) def func(): ... в def func(): ... decorator = test_pass(ps) # В два шага для понятности func = decorator(func)

Ответ 2



В Питоне функции - это есть объекты. То есть мы можем сними делать всё, что сможем сделать с объектами. Например как в случае с декоратором. передавать объект функции как аргумент. так как func это есть объект функции, а func() вызов ps = 'any argument' decorator = test_pass(ps) # возращает объект внутренней функции deco. func = decorator(func) # вызывается deco(f)

Недопонимание с кодом

#c #указатели


Наткнулся на код, по которому у меня возникает пару вопросов, если ответите, то буду
признателен

#include 
#include 

int isOdd(int a) {
    return (a % 2 != 0);
}

unsigned int filter(int *arr, unsigned size, int (*pred)(int), int** out) {
    unsigned i;
    unsigned j;
    *out = (int*) malloc(sizeof(int)*size);
    for (i = 0, j = 0; i < size; i++) {
        if (pred(arr[i])) {
            (*out)[j] = arr[i];
            j++;
        }
    }
    *out = (int*) realloc(*out, j*sizeof(int));
    return j;
}

int main () {
    int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    unsigned i;
    unsigned size;
    int *aOdd = NULL;

    size = filter(a, 10, isOdd, &aOdd);
    for (i = 0; i < size; i++) {
        printf("%d ", aOdd[i]);
    }

}


Вопрос №1:
Зачем требуются явные преобразования такого вида? 

*out = (int*) malloc(sizeof(int)*size);
*out = (int*) realloc(*out, j*sizeof(int));


Они же излишни, если я не ошибаюсь.

Вопрос №2: Что происходит в строках, которые я выделил восклицательными знаками?

    unsigned int filter(int *arr, unsigned size, int (*pred)(int), int** out) {
    unsigned i;
    unsigned j;
    *out = (int*) malloc(sizeof(int)*size); /* !!!!!!!!!! */
    for (i = 0, j = 0; i < size; i++) {
        if (pred(arr[i])) {
            (*out)[j] = arr[i]; /* !!!!!!!!!! */
            j++;
        }
    }
    *out = (int*) realloc(*out, j*sizeof(int)); /* !!!!!!!!!! */
    return j;
}


Вопрос №3: Разве не легче было реализовать функцию из вопроса №2 таким образом (просто
через указатель, а не через указатель на указатель)

unsigned int filter(int *arr, unsigned size, int (*pred)(int), int* out) {
    unsigned i;
    unsigned j;
    for (i = 0, j = 0; i < size; i++) {
        if (pred(arr[i])) {
            *(out + j) = arr[i];
            j++;
        }
    }

    return j;
}


Есть ли существенные различия или даже преимущества между функцией из 
вопроса №2 и функцией из вопроса №3?
    


Ответы

Ответ 1



Вопрос №1: Зачем требуются явные преобразования такого вида? Для C не нужны. Для C++ необходимы, т.к. в C++ неявное преобразование из void* запрещено. Вопрос №2: Что происходит в строках, которые я выделил восклицательными знаками? 1) Выделение памяти для size int'ов. 2) Копирование элемента, удовлетворяющего предикату в только что выделенный массив. 3) Отрезаем не заполненный кусок массива данных Вопрос №3: Разве не легче было реализовать функцию из вопроса Они дают разный результат Есть ли существенные различия или даже преимущества между функцией из вопроса №2 и функцией из вопроса №3? Для варианта из вопроса №2 память выделяется непосредственно в функции, а потом усекается. Для варианта из третьего вопроса эта ответственность ляжет на вызывающую сторону. Преимущества и недостатки есть у обоих способов. Всё зависит от того, как их использовать.

Ответ 2



Я уже писал об этом раньше. Когда вы реализуете функцию, размер массива-результата которой заранее неизвестен, т.е. становится известен только внутри функции, то возникает проблема выделения правильного количества памяти для сохранения результата. Пользователь (т.е. вызывающий код) в общем случае заранее эту память выделить не может, ибо пока еще не знает, сколько памяти понадобится. В таких случаях есть несколько основных стратегий: В некоторых случаях заранее известен максимально возможный размер результата, можно выделить память заранее "по максимуму" и такое максимальное выделение является, условно выражаясь, "разумным". Это как раз ваш случай. И да, ваш №3 будет прекрасно работать по этой схеме. Пользователь только обязан предоставить выходной массив размера не менее size и иметь в виду, что в общем случае не весь он будет использован. Выделять память внутри функции: либо сразу, когда ее размер становится известен, либо инкрементально по мере накопления результата, либо "по максимуму" с последующим урезанием, либо еще как. Это ваш вариант №2. Проблема этого подхода в том, что выделение памяти в таком случае нелегко кастомизировать. В простейшем случае будет просто malloc, как у вас в примере. А может пользователю не нужен malloc? Реализовать функцию по образу и подобию snprintf, т.е. предоставить возможность "холостого" прохода, который лишь подсчитывает и возвращает размер результата, но пока не формирует результат. Получив подсчитанный размер, пользователь выделяет память любым удобным для него образом и затем снова вызывает ту же функцию, теперь уже для "настоящего" прохода, т.е. для формирования результата в буфере. То есть ваши №2 и №3 - два альтернативных подхода к решению задачи. Оба способа по-своему правильны.

Ответ 3



В дополнение к ответу Groessmah добавлю пояснение к 3-му вопросу: Ваша ф-ция реализована ошибочно: во-первых отсутствует выделение памяти - у вас указатель все еще указывает на NULL! А для того, чтобы выделить память в ф-ции и нужен указатель на указатель, иначе память выделить вы сможете, но вот сделат так, чтобы нужный нам указатель указывал на нее - нет. Во-вторых, если мы и выделим память до вызова ф-ции, урезать ее в ф-ции, опять таки, не получится.

Возможность остановить анимацию css

#css #css3 #html5 #css_animation


Здравствуйте!

Есть ли возможность остановить анимацию css с той позиции, когда нажата кнопка Pause
и снова запустить с места остановки

На данный момент при checked Pause - анимация сбрасывается

Решение на javascript есть. Хотелось бы решение на css.

Код Fiddle



#play {
  display: none;
}

#play+label[for=play] {
  display: inline-block;
  color: #fff;
  cursor: pointer;
  font-size: 13px;
  z-index: 99;
  padding: 5px;
  background: #37A000;
  margin-bottom: 15px;
}

#play+label[for=play]>span:nth-of-type(2),
#play:checked+label[for=play]>span:nth-of-type(1) {
  display: none;
}

#play:checked+label[for=play] {
  background: tomato;
}

#play:checked+label[for=play]>span:nth-of-type(2) {
  display: block;
}

.progress {
  height: 15px;
  background: #555;
  position: relative;
}

.progress:after {
  width: 0;
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: #37A000;
  animation-play-state: paused;
}

#play:checked+label[for=play]~.progress:after {
  animation: animProgress 7s linear infinite;
}

@keyframes animProgress {
  100% {
    width: 100%;
  }
}




Ответы

Ответ 1



Лови. #play { display: none; } #play + label[for=play] { display: inline-block; color: #fff; cursor: pointer; font-size: 13px; z-index: 99; padding: 5px; background: #37A000; margin-bottom: 15px; } #play + label[for=play] > span:nth-of-type(2), #play:checked + label[for=play] > span:nth-of-type(1) { display: none; } #play:checked + label[for=play] { background: tomato; } #play:checked + label[for=play] > span:nth-of-type(2) { display: block; } .progress { height: 15px; background: #555; position: relative; } .progress:after { width: 0; content: ''; position: absolute; top: 0; left: 0; height: 100%; background: #37A000; animation: animProgress 7s linear 1; animation-fill-mode: forwards; } #play ~ .progress:after { animation-play-state: paused; } #play:checked ~ .progress:after { animation: animProgress 7s linear 1; animation-fill-mode: forwards; } @keyframes animProgress { from { width: 0 } to { width: 100% } }
p.s. В примере выставил один цикл.

Ответ 2



Поменял немного ответ Kniha m. Добавил цикличность в анимацию. Так как было у автора. #play { display: none; } #play+label[for=play] { display: inline-block; color: #fff; cursor: pointer; font-size: 13px; z-index: 99; padding: 5px; background: #37A000; margin-bottom: 15px; } #play+label[for=play]>span:nth-of-type(2), #play:checked+label[for=play]>span:nth-of-type(1) { display: none; } #play:checked+label[for=play] { background: tomato; } #play:checked+label[for=play]>span:nth-of-type(2) { display: block; } .progress { height: 15px; background: #555; position: relative; } .progress:after { width: 0; content: ''; position: absolute; top: 0; left: 0; height: 100%; background: #37A000; animation: animProgress 7s linear infinite; animation-play-state: paused; } #play:checked+label[for=play]~.progress:after { animation-play-state: running; } @keyframes animProgress { 100% { width: 100%; } }


Запуск процесса на нескольких ядрах

#linux


У меня есть 2 серверных Xeon процессора с 32  ядрами  и установленной Linux Ubuntu
16.04. У меня есть питоновский скрипт,при запуске скрипта он выполняется на 1 ядре
и это занимает достаточно длительное время.Может знает кто-нибудь как распараллелить
вычисление этого скрипта,чтобы его обрабатывали сразу несколько ядер?
    


Ответы

Ответ 1



Необходимо понять, что имеющийся скрипт делает какие части возможно выполнять независимо друг от друга переписать скрипт используя процессы, потоки или что угодно другое для разделения одного потока команд на несколько Какого-то волшебного слова или директивы use many cores в императивных языках программирования нет. Потому что сама программа является последовательностью команд. Одну последовательность только одно ядро CPU выполнять и может. Нельзя одну последовательность команд параллельно разделить на 10 ядер и получить в результате осмысленный результат. Возможно, вам подойдёт и простейший способ загрузки нескольких ядер - просто запустить несколько копий программ, каждая из которых будет обрабатывать часть задач. Например, если вам нужно сжать 100 картинок - вы это можете сделать в одном цикле последовательно либо же запустить 10 программ, каждая из которых будет в том же самом цикле совершенно так же последовательно обрабатывать, но не все 100 изображений, а каждый из процессов отдельные 10. Это позволит скорей всего не очень сложным изменением кода использовать не 1, а 10 ядер. Возможно, удобнее будет взять какой-либо менеджер очередей: запускается нужное число (более простых) однопоточных программ, которые периодически запрашивают из очереди задачу - и выполняют эту задачу. Соответственно одна задача выполняется на одном ядре, но группа задач может выполняться одновременно разными копиями скрипта.

Вопрос про оптимизацию кода

#javascript #оптимизация #google #замыкания


Сегодня попробовал google closure. 
Заметил, что цифры в условиях он ставит на первое место:

Оригинал

A.keyLis.blockCtrlAlt.fined(e.keyCode) !== -1 && e.ctrlKey


После closure

-1 !== A.keyLis.blockCtrlAlt.fined(a.keyCode) && a.ctrlKey


Вопрос следующий- как это оптимизирует код?
    


Ответы

Ответ 1



Нет, это не оптимизация. Это Йода стайл. Когда то он помогал избежать ошибок. Если вместо a == 1 написать a = 1, то будет немного не то, что ожидается, но многие старый компиляторы/интерпретаторы пропускали. А вот так 1 = a сразу ошибка. Сейчас многие компиляторы/интерпретаторы умеют "видеть" код вида a=1 в условиях и ругаются. Как по мне, то сейчас так уже писать не нужно.

Отличие файлов SharedPreferences от обычных файлов

#android #файловая_система #android_shared_preferences


Определение SharedPreferences из документации:


  Объект SharedPreferences указывает на файл, содержащий пары
  "ключ-значение", и предоставляет простые методы для чтения и записи.
  Управление каждым файлом SharedPreferences осуществляется с помощью
  инфраструктуры и может быть частным или общим.


А чем отличаются файлы, используемые SharedPreferences, от обычных файлов в файловой
системе Android? Одно из отличий, как написано в той же документации, если я правильно
понимаю, состоит в строго определённой структуре файла (набор пар "ключ-значение").
А есть ли ещё отличия? Например, эти файлы можно прочитать только программно (т.е.
можно прочитать только из приложения/приложений, которые обращаются к этим SharedPreferences,
а открыть из файловой системы их нельзя) или же это неверно?
    


Ответы

Ответ 1



Файлы SharedPreferences это обычные файлы с расширением .xml которые располагаются в подкаталоге конкретного приложения. При этом права доступа к файлу прописываются такие же как и всем остальным, которые принадлежат данному приложению. Соответственно получить доступ к нему можно не только программно, но и из файловой системы. Другим программам на устройстве получить доступ к данному файлу не удастся,так как они не имеют соответствующих прав, за исключением тех программ которые имеют права root или же подписаны тем же сертификатом, что и программа которой принадлежит SharedPreferences

Вирусы в WordPress

#wordpress #вирусы


Ограничиваю доступ ко всем файлам и папкам 550, а вирусы все равно появляются.
Как это остановить?  

Это такие вирусы:


'6', '0'=>'l', '3'=>'t', '2'=>'N', '5'=>'z', '4'=>'5', '7'=>'R',
'6'=>'H', '9'=>'C', '8'=>'4', 'A'=>'u', 'C'=>'I', 'B'=>'Z', 'E'=>'k', 'D'=>'d', 'G'=>'r',
'F'=>'E', 'I'=>'O', 'H'=>'c', 'K'=>'9', 'J'=>'7', 'M'=>'n', 'L'=>'S', 'O'=>'a', 'N'=>'J',
'Q'=>'p', 'P'=>'D', 'S'=>'m', 'R'=>'W', 'U'=>'A', 'T'=>'f', 'W'=>'X', 'V'=>'0', 'Y'=>'e',
'X'=>'K', 'Z'=>'U', 'a'=>'Q', 'c'=>'q', 'b'=>'2', 'e'=>'b', 'd'=>'x', 'g'=>'M', 'f'=>'g',
'i'=>'3', 'h'=>'h', 'k'=>'8', 'j'=>'1', 'm'=>'j', 'l'=>'P', 'o'=>'Y', 'n'=>'v', 'q'=>'y',
'p'=>'s', 's'=>'i', 'r'=>'T', 'u'=>'F', 't'=>'B', 'w'=>'V', 'v'=>'w', 'y'=>'o', 'x'=>'G',
'z'=>'L');
eval/*ralhc*/(wfhrwni($riqlqi, $slnskf));
}



    


Ответы

Ответ 1



ограничиваю доступ ко всем файлам и папкам 550 Не нужно трогать права вообще. Это никакое не "ограничение" и никак не влияет на безопасность сайта. Этими правами регулируются доступы различных процессов сервера. А поскольку доступ ко всем файлам имеет процесс php, то изменяя права, можно просто поломать нормальную работу сайта. вирусы все равно появляются, как это остановить? 1. Причины появления: Темы с помоек ("помойки" - сайты с "бесплатными" темами. Которые они, кстати, называют "шаблонами" - первый признак помойки.) Плагины оттуда же. Устаревшие темы и плагины с платных маркетов. Темы и плагины некогда из оф каталога, но древние и/или уже удалённые оттуда (удаляются как правило как раз по причине найденных уязвимостей) Установка на сайт разных левых скриптов (как правило от малоизвестных рекламных сетей и тп) Вирусы на ПК Дырявый хостер 2. Что делать чтобы обезопасить сайт: Использовать темы и плагины только из оф. каталога: https://wordpress.org/themes/: https://wordpress.org/plugins/ Если покупать, то только у надёжных продавцов: https://wordpress.org/themes/commercial/ Следить за обновлениями ВП и компонентов. Следить за безопасностью ПК и для администрирования сайтов использовать отдельный браузер/профиль. Использовать нормальный хостинг (избегать услуг хостинга от регистраторов доменов). Не ставить никаких скриптов из непонятных источников (в т.ч. и скопипащеных из интернета из мануалов аля "фича без плагинов"). 3. Что делать, если уже начались проблемы: Закрыть доступ к сайту всем, кроме себя. Заменить ядро ВП (каталоги wp-admin, wp-includes) и файлы в корне, кроме wp-config.php, .htaccess и созданных вами (robots.txt, и т.п.) через их первоначальное удаление. Свою версию ВП можно скачать отсюда: https://ru.wordpress.org/releases/ Проверить .htaccess. Сделать ревизию плагинов и тем. Удалить древние и неизвестного происхождения. Обновить что можно или заменить при необходимости. После чего просканировать с помощью https://revisium.com/ai/ все файлы и дамп базы. Глазами и поиском ("eval" и т.п.) по хостингу посмотреть на файлы/каталоги выше уровня www (public_html). Иногда и там встречаются следы. Примечание. Можно использовать из оф. каталога и некоторые древние простые плагины, такие, как плагины траслитерации. Но, принимая решение относительно других, стоит проанализировать их код.

Как работает приведение типов ключей при создании объекта?

#javascript




var obj = { "1": 0, 1: 9, 2: 3 } 
console.log(obj["1"]); // 9
console.log(obj);




Почему вернулось значение свойства 1, а не "1"?
Куда пропало свойство 1?
    


Ответы

Ответ 1



Потому что ключом в объекте всегда является строка (ну ладно, ещё symbol, но он тут не при чём). Получается, ты в литеральную запись объекта включаешь два одинаковых свойства (разрешено в ES3-, ES5 non strict, ES6+ в любом режиме) и последнее из свойств побеждает (перезаписывает более раннее значение).

Роль interface в Java

#java #dependencies #inversion_of_control


Здравствуйте, давно читаю разные туториалы и много где встречаю должно быть мало
зависимостей, как я понял это все достигается при помощи interface и IoC. Нашел много
примеров но так сути и не понял как правильно это достигать... К примеру у меня есть
проект с моделями(таблицы из БД) и сервисы(классы для выполнения каких=либо действий
над ними), и что получается мне для каждого сервиса писать интерфейс его действий?
Я понимаю что если добавится другой класс мы просто имплементим его и ничего менять
не нужно практически. Но с другой стороны много лишнего кода и классов. Может быть
мне кто-нибудь сможет подробно объяснить как достигнуть минимизации зависимостей на
примерах кода Java или просто на словах, чтобы я уловил смысл?
    


Ответы

Ответ 1



Для чего вообще нужно минимизировать зависимости? Фредерик Брукс, автор статьи «Серебряной пули нет» утверждал, что производство программного обеспечения дело трудное, и в ближайшее время не появится ничего, что сделает его проще. Это было в середине 80-х. Через 10 лет Брукс изучил, изменилось ли что-нибудь кардинально в индустрии. Оказалось, что нет. Правда, один из подходов выглядел многообещающе — повторное использование кода. Речь о том, что, написав большую систему, и приступая к написанию другой, мы могли бы взять готовые куски кода и использовать их повторно. Фактически, мы могли бы сократить работу минимум на 30%. Этому мешает то, что части системы сильно сцеплены (couple) друг с другом. Для борьбы со сцепленностью придуманы без малого десятки техник. Часть из них дублируют друг друга на разных уровнях детализации. Вначале программы были не очень большими, и программисты делали независимыми отдельные функции. Скажем, предпочитали чистые функции, значение которых зависело только от аргументов, следовательно, их можно было безболезненно перенести в другой проект. Предпочитали модули с высокой связностью, но малой сцепленностью. В современных ОО языках предпочитают классы с единственной ответственностью. Когда программы стали слишком большими, модули объединили в слои (уровни) и задали чёткое правило направления зависимостей: нижние уровни не могут зависеть от верхних. Никогда. В классическом трёхзвенном приложении уровень представления зависит от уровня предметной области, а тот, в свою очередь, от уровня доступа к данным. Presentation → Domain → Data Access Для примера возьмём интернет-магазин. Одной из сущностей магазина является Заказ (Order). Этот класс принадлежит к уровню предметной области, потому что вся работа интернет-магазина строится вокруг Заказов. Если вы используете паттерн MVC в построении веб-приложения, то заведовать заказами будет Контроллер Заказов (OrderController). Этот класс принадлежит к уровню представления. Значит, класс OrderController может знать и использовать Order, а Order ничего про OrderController знать не может. В этом есть глубокий смысл. Предположим, у вас работает не только веб-приложение, но фоновые сервисы, которые, по сути являются консольными приложениями. Они запускаются с заданным интервалом и что-то делают с заказами. Очень правильно в этом случае повторно использовать весь код, реализующий Заказы и их сохранение в БД. Но чтобы это сделать, надо чётко понимать, что является представлением, а что нет. OrderController реагирует за запросы HTTP, и у него есть такие штуки, как URI запроса, текущий пользователь и прочее. Но ничего этого нет у самого Заказа. Эта ошибка встречается часто: в классах предметной области хранятся дескрипторы окна, или данные, специфичные для веб-приложений. На самом деле класс Order не может строить никаких предположений о том, в какой среде его будут использовать. Вопрос, трудно ли будет создать фоновые сервисы или оконные приложения, если приложение спроектировано правильно? Не очень трудно. Нам, конечно, придётся написать новый слой, но нам точно не нужно будет переписывать классы нижних уровней, в частности Order. Теперь опускаемся на уровень ниже, к данным. Предположим, все данные лежат в MySQL и мы для доступа к ним используем JDBC. SQL-запрос для постраничного списка заказов мы пишем сами, он в виде строковой константы находится в Java-коде: SELECT Orders.* FROM Orders ORDER BY Orders.CreatedAt LIMIT ? OFFSET ? На уровне доступа к данным у нас находятся классы Connection, ResultSet, Statement из пространства имён java.sql. Классы с верхних уровней могут к ним обращаться, то есть Order мог бы уметь создавать себя из ResultSet, а OrderController мог бы выполнять запросы с помощью Statement. Снова всё хорошо. Вопрос, трудно ли будет изменить способ хранения с MySQL на Oracle, или даже на что-нибудь вроде MongoDB? На этот раз гораздо труднее, чем раньше. Нам придётся вносить изменения не только в классы нижнего уровня, но и в Order, и в OrderController. В Oracle постраничный доступ требует другого синтаксиса, а для загрузки данных из MongoDB уже нельзя использовать ResultSet. Решение заключается в том, чтобы в данном месте инвертировать зависимость. Мы говорим, что не знаем заранее, как будем обращаться к данным. Вместо конкретных классов ResultSet и MongoCollection мы скажем: у нас точно будет какое-то внешнее хранилище из которого мы захотим постранично получать данные. Наверное, нам придётся узнавать и общее количество страниц. public interface OrderRepository { List ReadAll(int oneBasedPageNumber); int ReadTotalPages(); } Интерфейс Хранилище Заказов (OrderRepository) находится на уровне предметной области, и OrderController может использовать его. Реализация интерфейса для MySQL находится на уровне доступа к данным, но теперь зависимость инвертирована: доступ к данным зависит от предметной области. public MysqlOrderRepository implements OrderRepository { @Override public List ReadAll(int oneBasedPageNumber) { . . . } } Реализация MysqlOrderRepository видит Order и может создавать объекты Заказа. Зависимости теперь выглядят так: Presentation → Domain ← Data Access Из всего изложенного становятся понятно, что использовать интерфейсы для доступа к объектам предметной области не нужно, если этого не требуют специальные условия. Скажем так, Заказ в интернет-магазине — одна из базовых сущностей, и вряд ли вам потребуют две конкурирующие реализации Заказов. Точно также и сервисы предметной области интерфейсов не требуют. Бизнес-процесс оформления заказа фиксирован, поэтому его сразу можно реализовать в виде конкретного класса Сервис Оформления Заказов (OrderService). Использовать интерфейсы для объектов уровня представления также не нужно, потому что они находятся на самом верху и от них ничего не зависит. Интерфейсами имеет смысл закрывать только объекты и сервисы уровней ниже предметной области. Мы обозначили их как уровень Data Access, а Эрик Эванс, создатель DDD, предлагает называть их инфраструктурными. Соответственно, у нас может быть сервис рассылки электронных сообщений NotificationService. Это интерфейс уровня предметной области, чья реализация TwilioNotificationService находится на инфраструктурном уровне. При такой организации проекта мы получаем возможность быстро клонировать проект и дописать новый кусок. Хотим сделать консольное приложение? Берём готовые уровни предметной области и инфраструктуры, дописываем обвязку консольного приложения. Хотим перенести на СУБД Postgres? Берём готовые уровни предметной области и представления, дописываем реализацию хранилищ на PostreSQL. Зависимости остаются, но они упорядочены и позволяют изымать и подменять целые уровни приложения. Есть несколько случаев, когда интерфейсы могут появиться на высоких уровнях. Скажем, если в интернет-магазине могут быть разные способы начисления скидок, их удобно реализовать в виде паттерна Стратегия. По сути это будет иерархия однотипных классов, каждый из которых рассчитывает скидку на основании своих данных. Общие методы этих классов можно вынести в базовый интерфейс. В этом случае необходимость в интерфейсе диктуется уже не зависимостями, а способом реализации конкретного паттерна. Резюмирую: мы в действительности можем говорить о минимизации зависимостей, как об управлениями зависимостями. Мы не можем от них избавиться совсем, но мы можем их ограничивать. Для этого мы разбиваем приложение на слои, и вводим правило: все зависимости идут в одну сторону. Использовать можно только свои классы, либо классы слоя, от которого мы зависим. Ядром приложения, его солью является слой предметной области. Все слои, которые выше него, оставляем как есть, они и так от него зависят. Для слоёв, которые ниже него, инвертируем зависимости. На практике это означает, что мы вводим интерфейсы в слой предметной области, которые реализуем в нижних слоях.

Ответ 2



В Java интерфейсы имеет смысл рассматривать в совокупности с абстрактными классами. Они похожи, но имеют существенные отличия. Что-то мне подсказывает, что вопрос связан не именно с интерфейсами, а с обобщением кода в принципе. Интерфейсы не могут минимизировать код, а могут только помочь в его структурировании, тогда как абстрактные классы могут взять на себя часть общих методов, присущих их дочерним элементам, таким образом сократив общее количество кода. Интерфейс служит для объединения схожих элементов - для того, чтобы задать им обязательство имплементировать определенные методы. Например для ваших сервисов это могут быть методы CRUD. Маркерный интерфейс не имеет методов вообще. Наличие такого интерфейса у класса, и соответствующее его поведение, определяется из кода. Абстрактный класс выгодно отличается от интерфейса тем, что общие для всех дочерних элементов методы можно один раз описать в нем, а из дочерних элементов просто вызывать. Пример: Сайт написан на чистых сервлетах. Есть абстрактный класс-сервлет, от которого наследуются все остальные страницы-сервлеты сайта. В абстрактном классе есть два метода: Реализованный doResponse - общий для всех страниц сайта. Абстрактный preparePage - должен быть реализован индивидуально для каждой страницы. Index.java @WebServlet(name = "index", urlPatterns = {"/index.html"}) public class Index extends AbstractServlet { protected static char[] page; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doResponse(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doResponse(request, response); } @Override protected void preparePage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { StringBuilder stringBuilder = new StringBuilder(); ... creating page from template ... setPage(stringBuilder.toString().toCharArray()); } } AbstractServlet.java public abstract class AbstractServlet extends HttpServlet { protected char[] getPage() throws ServletException, IOException { return (char[]) this.getClass().getField("page").get(this.getClass()); } protected void setPage(char[] page) { this.getClass().getField("page").set(this.getClass(), page); } protected void doResponse(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter pw = response.getWriter(); if (this.getPage() == null) { this.preparePage(request, response); } pw.write(this.getPage()); } protected abstract void preparePage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; }

Ответ 3



Есть Очень классное видео ТУТ где объясняют лямбда выражения используя интерфейсы. Смотреть на скорости х2. После просмотра ты очнешься, как Нео из матрицы, со словами - "Я знаю лямбда и интерфейсы"

Как сверстать облако тегов на css?

#html #css #frontend


Сейчас готов кусок html и css к нему, но верстка не соответствует макету и непонятно,
как сделать hover при наведении и всплывающую подсказку над тегом.



.tags {
  padding: 80px;
  width: 380px;
  /* Style for "jQuery" */
  color: #ffffff;
  font-family: Roboto;
  font-size: 17px;
  font-weight: 300;
  line-height: 40px;
}

.tags a {
  white-space: nowrap;
  /* Style for "Rounded Re" */
  width: auto;
  border-radius: 13px;
  background-color: #090a0b;
  padding: 5px 10px 5px 10px;
  text-decoration: none;
  color: #ffffff;
}





При этом на выходе должно получится облако тегов с возможностью раскрыть его и при
наведении hover с подсказкой https://yadi.sk/i/t7ATcCq23SqXoq
    


Ответы

Ответ 1



ну вот как вариант body { background: #1e2429; } .tags { padding: 80px; width: 380px; /* Style for "jQuery" */ color: #ffffff; font-family: Roboto; font-size: 17px; font-weight: 300; line-height: 40px; } .tags a { white-space: nowrap; /* Style for "Rounded Re" */ width: auto; border-radius: 13px; background-color: #090a0b; padding: 5px 10px 5px 10px; text-decoration: none; color: #ffffff; position: relative; /* для подсказки */ } /* это нужно, если есть необходимость что бы можно было навести курсор на подсказку. Иначе будет исчезать */ .tags a:after { content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: 20px; visibility: hidden; } .tags a:hover:after { visibility: visible; } .tags a:hover { background: #eb1f63; } /* оформление плашки */ .tags__hide { position: absolute; left: 50%; position: absolute; left: 50%; transform: translateX(-50%); color: #000; background: #fff; padding: 5px 10px; line-height: 1; transition: all .3s; /* параметры для изчезновения/появления. Можете настроить как вам угодно */ visibility: hidden; opacity: 0; bottom: 0; } .tags a:hover .tags__hide { visibility: visible; opacity: 1; bottom: calc(100% + 15px); } /* треугольник */ .tags__hide:before { content: ''; width: 10px; height: 10px; background: #fff; position: absolute; bottom: -5px; left: 50%; margin-left: -5px; transform: rotate(45deg) }

Ответ 2



Пример * { padding: 0; margin: 0; box-sizing: border-box; } .tags-list { padding: 20px; margin: 25px 0; } .tags-list>li { display: inline-block; vertical-align: top; margin-right: 5px; margin-bottom: 5px; } .tags-list>li>a { position: relative; display: block; padding: 10px 15px; background: #000; color: #fff; border-radius: 15px; } .tags-list>li>a:hover { background: #f00; } .tags-list>li>a[data-tooltip]:before { position: absolute; left: 50%; top: -100%; background: #ccc; color: #000; height: 30px; line-height: 30px; padding: 0 15px; content: attr(data-tooltip); white-space: nowrap; transform: translateX(-50%); } .tags-list>li>a[data-tooltip]:after { position: absolute; left: 50%; top: -10px; margin-left: -7px; border-top: 7px solid #ccc; border-left: 7px solid transparent; border-right: 7px solid transparent; content: ""; } .tags-list>li>a[data-tooltip]:before, .tags-list>li>a[data-tooltip]:after { pointer-events: none; visibility: hidden; opacity: 0; transition: all .3s ease; } .tags-list>li>a[data-tooltip]:hover:after, .tags-list>li>a[data-tooltip]:hover:before { visibility: visible; opacity: 1; }

Ответ 3



Можно попробовать добавить псевдоэлемент ::before и скрыть его display: none;, а при наведении display: block;, скачать иконочный шрифт в виде всплывающего облака, но не уверен, надо проверять. При наведении: .tags a:hover { background: linear-gradient(to top right, #f5755a, #f136ef); }

Билдер для древовидной структуры данных?

#java #c_sharp #шаблоны_проектирования


Нужно реализовать паттерн билдер для древовидной структуры данных. Все что я пробовал,
показывает, что это очень сложно делать и крайне неудобно намного проще сделать через
несколько new.
Буду очень рад, если кто-то решал подобные проблемы и покажет пример такого билдера.
    


Ответы

Ответ 1



Допустим, мы хотим построить дерево. У нас есть узел public class Node { public int Value { get; set;} public Node Left { get; set;} public Node Right { get; set;} } Далее пример fluent билдера. То есть вызовы можно объединять в цепочки, чтобы построить дерево public class TreeBuilder { private InnerNode _root; private InnerNode _currentNode; private TreeBuilder(int value) { _root = new InnerNode() { Value = value }; _currentNode = _root; } public static TreeBuilder Create(int value) { return new TreeBuilder(value); } public TreeBuilder AddLeft(int value) { _currentNode.Left = new InnerNode() { Value = value, Parent = _currentNode }; return Left(); } public TreeBuilder AddRight(int value) { _currentNode.Right = new InnerNode() { Value = value, Parent = _currentNode }; return Right(); } public TreeBuilder Left() { _currentNode = _currentNode.Left; return this; } public TreeBuilder Right() { _currentNode = _currentNode.Right; return this; } public TreeBuilder Root() { _currentNode = _root; return this; } public TreeBuilder Parent() { _currentNode = _currentNode.Parent; return this; } public Node Build() { return Build(_root); } private Node Build (InnerNode node) { if (node == null) return null; return new Node() {Value = node.Value, Left =Build(node.Left), Right=Build(node.Right)}; } private class InnerNode { public int Value { get; set; } public InnerNode Left { get; set; } public InnerNode Right { get; set; } public InnerNode Parent { get; set; } } } Внутри билдера для представления не законченного дерева я использовал отдельный класс, так как этот класс имеет ссылку на родителя и с ним удобней ходить по узлам. По идее можно было накапливать информацию о строящемся объекта как понравится. Ну, и, собственно, использование: var root = TreeBuilder .Create(10) .AddLeft(5) .Parent() .AddRight(15) .AddLeft(10) .Build(); // 10 // / \ // 5 15 // / // 10

Ответ 2



Рискну привести исходники. Получилось довольно много кода: private static class Team { public final List players; public Team(List players) { this.players = Collections.unmodifiableList(players); } public static TeamBuilder builder() { return new TeamBuilder(); } static class TeamBuilder { private List playerBuilders = new ArrayList<>(); public TeamBuilder add(Player.PlayBuilder builder) { playerBuilders.add(builder); return this; } public Team build() { List players = new ArrayList<>(); for (Player.PlayBuilder playerBuilder : playerBuilders) players.add(playerBuilder.build()); return new Team(players); } } static class Player { public final String name; Player(String name) { this.name = name; } public static PlayBuilder builder() { return new PlayBuilder(); } static class PlayBuilder { private String name; public Player build() { return new Player(name); } public PlayBuilder setName(String name) { this.name = name; return this; } } } } Использовать так: Team.builder() .add(Team.Player .builder() .setName("first player")) .add(Team.Player .builder() .setName("second player")) .add(Team.Player .builder() .setName("third player")) .build(); Основная идея - это создание для каждого объекта своего билдера, который бы потом передавался другому и так далее.

Как правильно верстать горизонтальный список (меню)?

#html #css


Имеется пример списка:




Как правильно записать стили, чтобы сделать горизонтальное меню?

Просто есть вариант с float: left;, displat: inline; итп. Хочу увидеть, как делают
это профессионалы.



UPD: при li > display: inline-block; у li появляются боковые отступы, которые никак
не могу убрать, а чем проблема?

    


Ответы

Ответ 1



Пример с flexbox: * { margin: 0; padding: 0; } body { font-family: Monospace; font-size: 1.3rem; } .container { padding: 0 0.9375rem; } li { list-style-type: none; } a { text-decoration: none; color: white; } .navbar { background-color: crimson; } .navbar ul { display: flex; justify-content: flex-start; flex-wrap: wrap; } .navbar ul li { padding: 1rem; background-color: black; } Пример с flow-root & float: left: * { margin: 0; padding: 0; } body { font-family: Monospace; font-size: 1.3rem; } .container { padding: 0 0.9375rem; } li { list-style-type: none; } a { text-decoration: none; color: white; } .navbar { background-color: crimson; } .navbar ul { display: flow-root; } .navbar ul li { padding: 1rem; float: left; background-color: black; } Upd: Выделил li, сделал без отступов.

Ответ 2



Это один из вариантов.... flex. Вот, что-бы не приходилось правиь ответ надо сразу в вопросе отмечать что да как надо ul { margin: 0; padding: 0; display: flex; width: 100%; background: rgba(205, 115, 12, 0.1); flex-direction: row; justify-content: space-between; list-style: none; background: red; } li { width: 19%; background: green; text-align:center; }

Ответ 3



обычно li{display: inline-block} но если вам надо будет,чтобы значение list-style было отлично от none,тогда вам надо использовать li {float: left} в зависимости от адаптива,можно так же использовать flex или display: table, display: table-cell чтобы избавиться от отступов инлайн-блоков,задайте им font-size: 0; а контенту после задайте нужный размер шрифта

Две функции в самовызывающейся функции

#javascript #функции


Такой вопрос 

var bred = (function a() {
  return 1
}, function b() {
  return 2
})();


При вызове будет 2. Почему?
    


Ответы

Ответ 1



Потому что оператор запятая возвращает последний операнд. Всё равно что var bred = (1, 2); console.log(bred);

Как вывести на экран количество элементов в массиве имеющих конкретное значение?

#c_sharp #массивы


Я создала строковый массив,и рандомно присвоила элементам значения в помощью переменной
типа int (0,1) и вывела на консоль "черное" и "белое". Как вывести на экран еще и количество
элементов в массиве отдельно с названием "черное" и названием "белое"?

int numberOfBalls = 100;
string[] balls = new string[numberOfBalls];

Random rnd = new Random();
int a = rnd.Next(0, 2);

for (int i = 0; i < numberOfBalls; i++)
{
    a = rnd.Next(0, 2);
    if (a == 0)
        balls[i] = "beloe";
    else
        balls[i] = "chernoe";
}

for (int i = 0; i < numberOfBalls; i++)
{
     Console.WriteLine(balls[i]);
}

    


Ответы

Ответ 1



Воспользуйтесь методом расширения Count: Console.WriteLine(balls.Count(s => s == "beloe")); Классический вариант сделать тоже самое вручную в цикле: int count = 0; foreach (string s in balls) if (s == "beloe") ++count; Console.WriteLine(count); С помощью цикла for: int count = 0; for (int i = 0; i < numberOfBalls; ++i) if (balls[i] == "beloe") ++count; Console.WriteLine(count); Для подсчета количества "черных" код аналогичен.

Ответ 2



А можно в списке так и хранить 0 и 1 (занимает меньше места в памяти), а проверку черное/белое проводить перед выводом текста. Тогда сумма черных будет var black = balls.Sum(); без всяких циклов (т.к. в списке только 0 и 1, то сумма всех элементов даст нам сумму единиц, которая и есть количество "черных" элементов). А сумма белых: var white = numberOfBalls - black;

кнопка - блок или ссылка?

#html #css




Как лучше реализовывать такую кнопку? 

Первый вариант: 



div {
  width: 150px;
  text-align: center;
  background-color: #fff;
  border: 2px solid #ddd;
  
}

a {
  display: inline-block;
  padding: 3px 0;
  width: inherit;
  text-decoration: none;
  text-transform: uppercase;
  color: red;
}





Или же второй вариант:



a {
 display: block;
 width: 150px;
 padding: 3px 0;
 text-decoration: none;
 text-align: center;
 text-transform: uppercase;
 color: red;
 border: 2px solid #ddd;
load more



    


Ответы

Ответ 1



Если это кнопка, то надо использовать тег если же у этого элемента предназначение переадресовывать пользователя куда-то дальше, то делай ссылкой.

Ответ 2



Второй вариант через ссылку кажется значительно проще и лучше, ссылки приспособлены уже к перенаправлению, а через "тык" по div это все таки костыль, так же как и использовать div, а внутри него button

Как укоротить код с обнулением возвращаемого значения?

#java #любой_язык


Стало интересно, можно ли заменить данный код как то покороче? без использования
временной переменной 
Мне нужно по возвращению значения "сбрасывать" его же

private static int a;
a = ...;
public static int foo() {
    int t = a;
    a = 0;
    return t;
}


Вопрос из разряда "как поменять числа местами без использования мат.операторов"
    


Ответы

Ответ 1



Не думаю что имеет смысл делать подобные "оптимизации", но можно еще так поизвращаться: public static int foo() { try { return a; } finally { a = 0; } }

Ответ 2



Ваш код вполне норм, я только рекомендовал бы чуть расширить интерфейс до полноценного getSet: private static int v = 0; public static int getReset() { return getSet(0); } public static int getSet(int a) { int t = v; v = a; return v; } public static void main(String args[]) { v = 42; System.out.printf("%d, %d", getReset(), getReset()); } Однако, если мсье желает извращений, всегда можно выполнить нечто вроде: public static int getReset() { return v + (v=0); } public static int getSet(int a) { return v + (v=a)-a; } // Могут быть проблемы с переполнением, но могут и не быть, я не уверен :) Ну и классическое решение с атомарностью операции: private static final AtomicReference v = new AtomicReference<>(); public static int getReset() { return getSet(0); } public static int getSet(int a) { return v.getAndSet(a); } public static void main(String args[]) { v.set(42); System.out.printf("%d, %d", getReset(), getReset()); }

Ответ 3



private static AtomicInteger a = new AtomicInteger(...); public static int foo() { return a.getAndSet(0); }

Есть ли бóльшая пустота чем undefined?

#javascript #массивы


#delete #undefined #array #empty

Да, есть.

Думаю, всем известно, что для удаления элемента, в JS, используется undefined:

lеt variable = 'string'
variable = undefined


Им не часто пользуются, ведь в JS работает автоматический сборщик мусора, и мало
кто заботится об удалении элементов. Ещё реже встречаются люди, которые знают о существовании
метода delete, а тем более те, кто замечал различия в использовании undefined и delete.

let o = {
    A: 9,
    B: 9,
}
delete o['A']
console.log(
    Object.keys(o)//массив//["B"]//length: 1
);


Далее в моём вопросе, и следующем за ним ответе, будет рассмотрен частный, но очень
важный, случай различия в использовании undefined и delete в контексте массивов.

Итак (барабанная дробь) внимание, вопрос…

В чём различия при удалении элемента массива методами undefined и delete и какие
серьёзные и не очень последствия за этим следуют?

let arr = ['A','B','C','D','E','F']
delete arr[0]
arr[1] = undefined
arr[2] = void 0

    


Ответы

Ответ 1



Ещё реже встречаются люди, которые знают о существовании метода delete delete - оператор, а не метод! В чём различия при удалении элемента массива методами undefined и delete Присвоение undefined и оператор delete не удаляют элемент массива. Они "удаляют"/устанавливают значение, содержащееся в массиве. Сам элемент массива, после такого "удаления" остается - он становится не определенным, но позволяет выполнять операции с ним (смысл термина элемент !== смыслу термина содержимое элемента. Хотя, безусловно, ==). А различие в том, что присвоение undefined - это присвоение значения, со всеми вытекающими последствиями... тогда как delete, именно удаляет содержимое элемента. Для удаления элементов массива, в JavaScript существует Array.splice(). Прямое назначение метода как раз в этом (и в добавлении элементов). А delete - предназначен для удаления свойств объектов.

Ответ 2



Главное различие - что оператор delete удаляет элемент массива. Хоть при этом длинна массива не изменится и адресовать удалённый элемент вы по прежнему сможете. Но оператор in не обнаружит элемент удалённый таким способом: let arr = ['A','B','C','D','E','F'] arr[2] = undefined console.log(2 in arr) // ===> true delete arr[3] console.log(3 in arr) // ===> false Подробнее тут

Ответ 3



В: В чём различия при удалении элемента массива методами undefined и delete ? О: оператор delete удаляет пару «ключ-значение». В: Какие серьёзные и не очень последствия за этим следуют? О: так как на месте удалённого элемента с помощью delete остаётся empty (дырка) - весь второй раздел будет посвящён сравнению поведения операторов: for for in for of и некоторых методов: Array.forEach Array.map Array.filter Object.keys Object.values при работе с массивами, содержащими empty или undefined. Сразу хочу сделать заявление: Здесь будут рассмотрены только массивы Array! Здесь не будут рассматриваться типизированные массивы вроде: Int16Array; и всякие: Set, NodeList, ArrayBuffer (да-да, кое что из этого списка не массив). И ещё, небольшое замечание: иной раз не помешает убедиться что вы работаете с массивом (если собираетесь его модифицировать) а не с [Symbol.iterator]: function*, например. структура: немного теории как оно выглядит в консоле chrome , filefox и stackoverflow последняя запятая игнорируется функции, используемые мной здесь для тех, кто не хочет использовать empty и вообще не хочет читать многабукаф ибо где ещё почитать ищу информацию много практики для иллюстрации "проблемы" count замеры времени персонально для @yar85 оператор расширения (spread) 1. немного теории https://learn.javascript.ru/array-methods#удаление-из-массива оператор delete удаляет пару «ключ-значение». да, и в этом месте, в массиве, образуется "дырка" (empty), если попробовать прочитать значение из этой "дырки", то оно будет undefined Это – все, что он делает. на самом деле, оператор delete сразу освобождает память, а ещё возвращает true/false но в контексте элементов массива нас это не интересует, т.к. он всегда будет возвращать true (даже в случае с empty и undefined) Обычно же при удалении из массива мы хотим, чтобы оставшиеся элементы сдвинулись и заполнили образовавшийся промежуток. Поэтому для удаления используются специальные методы: из начала – shift, с конца – pop, а из середины – splice с shift и pop всё как всегда. а вот при работе со splice есть небольшой нюанс и, на самом деле, связан он с оператором расширения ( ... spread ) - с помощью splice не получится вставить empty элемент/ы, а spread превращает empty в undefined. 1.1 как оно выглядит в консоле chrome , filefox и stackoverflow ```js let arr = [0,1,2,3,4,5] delete arr[1] delete arr[2] arr[3] = undefined arr[4] = undefined console.log(arr) // эквивалентно // console.log([0,,,undefined,undefined,5]) ``` в консоле chrome : [ 0, empty × 2 , undefined, undefined, 5 ] в консоле filefox : [ 0, <2 empty slots> , undefined, undefined, 5 ] в консоле stackoverflow : [ 0, undefined, undefined, undefined, undefined, 5 ] как вывести в stackoverflow : ```js log(() => // "[ 0, empty, empty, undefined, undefined, 1 ]" arrToString([0,,,undefined,undefined,1,])) // <- запятая в конце ``` 1.2 последняя запятая игнорируется относительно недавно появилась возможность писать в конце запятую, которая игнорируется (что при создании объектов, что при создании массивов) ```js let a = ['A','B'] let b = ['A','B',] // <- запятая в конце log(() => Object.keys(a)) // ["0", "1"] log(() => Object.keys(b)) // ["0", "1"] log(() => a.length) // 2 log(() => b.length) // 2 ``` 1.3 функции, используемые мной здесь let group = _f => { console.group(_f.name || ((_f.prototype) ? _f : 'anonym')) try { _f() } catch (_e) { console.log(_e.stack) } console.groupEnd() } let log = (_f) => _f instanceof Function ? console.log(_f,_f()) : console.log(_f) group(() => { let hw = () => 'Hello World' // --> // вывод в консоле хрома log(hw) // () => 'Hello World' "Hello World" log(() => 'Hello World 2') // () => 'Hello World 2' "Hello World 2" // <-- }) group(() => { // --> // я же буду писать в комментариях только правую часть log(() => arrToString(['hello','world'])) // "[ hello, world ]" log(() => arrToString([1,,,undefined,undefined,2])) // "[ 1, empty, empty, undefined, undefined, 2 ]" // ----------- // ОСТОРОЖНО ! // ----------- // // вывод в консоле хрома log(() => arrToString([1,[11,,22],,undefined,undefined,2])) // "[ 1, 11,,22, empty, undefined, undefined, 2 ]" // <-- }) group(() => { throw new Error('qwa') }) function arrToString(_arr) { if (Object.prototype.arrToString.call(_arr) !== "[object Array]") throw new TypeError('_arr !== "[object Array]"') let res = [] let val = null; for (var i = 0; i < _arr.length; i++) { val = _arr[i] // проверка на `empty` // эквивалентно if (Object.keys(_arr).indexOf(''+i) !== -1) { if (i in _arr) { // проверка на `undefined` if (val === undefined) { res.push('undefined') } else { // res.push(String(val)) res.push('' + val) } } else { res.push('empty') } } //--- return `[ ${res.join(', ')} ]` } 1.4. для тех, кто не хочет использовать empty и вообще не хочет читать многабукаф ибо неожиданная встрече с empty в чужом коде может вызвать головную боль ; ) поэтому делаем заметку в голове и кликаем по звёздочке вверху пример создания массива заданной длинны с помощью конструктора Array : ```js let arr1 = Array(5) // == [,,,,,] log(() => arr1) // [empty × 5] let arr2 = Array.from({ length: 5 },(_key,_index) => undefined) log(() => arr2) // [undefined, undefined, undefined, undefined, undefined] ``` для перебора используйте только for (var _i=0; i функция) // результат в консоле он не охватывает все возможные методы и ситуации, а лишь демонстрирует ключевые моменты 2.1 для иллюстрации "проблемы" JQuery http://api.jquery.com/jquery.each/ let arr = [,,,] let count = null console.log(`arr.length: ${arr.length}`) { console.log('$.each') count = 0 $.each(arr,_k=>{ count++ }) console.log(`count: ${count}`) // count: 3 } { console.log('arr.forEach') count = 0 arr.forEach(_k=>{ count++ }) console.log(`count: ${count}`) // count: 0 } underscorejs http://underscorejs.ru/ Кроме того, Underscore умеет делегировать вызовы, т.е. если код выполняется в современном браузере, который имеет нативные реализации таких методов, как: forEach, map, reduce, filter, every, some и indexOf, то будут вызваны именно они. ничего не предвещало проблемы - простая функция сложения дана функция let sum = (arrOfNumbers) => { let res = 0 arrOfNumbers.forEach(_number => { res += _number }) return res } и массив let arr = [ 10, 3, 5 ] проверка с применением delete arr[1] () => sum(arr) 15 проверка с применением arr[1] = undefined () => sum(arr) NaN исходники: // /* group(function sum() { let sum = (arrOfNumbers) => { let res = 0 arrOfNumbers.forEach(_number => { res += _number }) return res } let a = 10,b = 3,c = 5,Arr = () => [a,b,c] group(function testDelete() { let arr = Arr(); log(() => arrToString(arr)) // "[ 10, 3, 5 ]" delete arr[1] log(() => sum(arr)) // 15 }) group(function testUndefined() { let arr = Arr(); log(() => arrToString(arr)) // "[ 10, 3, 5 ]" arr[1] = undefined log(() => sum(arr)) // NaN }) }) // */ 2.2 count дано два массива let a = [,,,'k3'] let b = [undefined,undefined,undefined,'k3'] суть теста - перебрать элементы массива и посчитать "тики" результат: count () => Object.keys(a) ["3"] () => Object.values(a) ["k3"] () => Object.keys(b) (4) ["0", "1", "2", "3"] () => Object.values(b) (4) [undefined, undefined, undefined, "k3"] test [,,,'k3'] for() => count: 4 for in() => count: 1 for of() => count: 4 _arr.forEach() => count: 1 _arr.map() => count: 1 _arr.filter(_k => true)() => count: 1 перед фильтрацией [ empty, empty, empty, k3 ] после [ k3 ] test [undefined,undefined,undefined,'k3'] for() => count: 4 for in() => count: 4 for of() => count: 4 _arr.forEach() => count: 4 _arr.map() => count: 4 _arr.filter(_k => true)() => count: 4 перед фильтрацией [ undefined, undefined, undefined, k3 ] после [ undefined, undefined, undefined, k3 ] исходники: group(function count() { let a = [,,,'k3'] let b = [undefined,undefined,undefined,'k3'] log(() => Object.keys(a)) log(() => Object.values(a)) log(() => Object.keys(b)) log(() => Object.values(b)) let o = { 'for'(_arr) { let count = 0 for (var i = 0; i < _arr.length; i++) { count++ } return(`count: ${count}`) }, 'for in'(_arr) { let count = 0 for (var i in _arr) { count++ } return(`count: ${count}`) }, 'for of'(_arr) { let count = 0 for (var i of _arr) { count++ } return(`count: ${count}`) }, '_arr.forEach'(_arr) { let count = 0 _arr.forEach(_k => { count++ }); return(`count: ${count}`) }, '_arr.map'(_arr) { let count = 0 _arr.map(_k => { count++ }); return(`count: ${count}`) }, '_arr.filter(_k => true)'(_arr) { let count = 0 let res = [] let before = `перед фильтрацией ${arrToString(_arr)}` let after = null _arr = _arr.filter(_k => { count++ return true }); res.push(`count: ${count}`) after = `после ${arrToString(_arr)}` res.push(before) res.push(after) return res.join(' ') }, // 'for'(){}, } let o2 = { "test [,,,'k3']"() { Object.values(o).forEach(_f => { log(`${_f.name}() => ${_f(a)}`) }) }, "test [undefined,undefined,undefined,'k3']"() { Object.values(o).forEach(_f => { log(`${_f.name}() => ${_f(b)}`) }) }, } Object.values(o2).forEach(group) }) 2.3 замеры времени дано: две матрицы (двумерный массив) matrixA и matrixB ширина = 1366 высота 768 это характеристики моего монитора каждая из них в самом конце (нижний правый угол монитора) содержит единичку matrixA состоит из empty matrixB состоит из undefined задача: запустить таймер, найти единичку (в самом конце), и остановить таймер. ответ в миллисекундах: () => test_for_in(matrixA) 2 () => test_for_in(matrixB) 206 () => test_for_of(matrixA) 122 () => test_for_of(matrixB) 130 () => test_for(matrixA) 122 () => test_for(matrixB) 115 решение: group(function matrix() { let width = 1366 let height = 768 let a = _n => Array(_n) let matrixA = Array.from({ length: height },() => a(width)) setLast(matrixA) let b = _n => Array.from({ length: _n },() => undefined) let matrixB = Array.from({ length: height },() => b(width)) setLast(matrixB) log(() => test_for_in(matrixA)) log(() => test_for_in(matrixB)) log(() => test_for_of(matrixA)) log(() => test_for_of(matrixB)) log(() => test_for(matrixA)) log(() => test_for(matrixB)) function setLast(matrix) { let lastArr = matrix[matrix.length - 1] lastArr[lastArr.length - 1] = 1 } function test_for_in(matrix) { let start = null let end = null start = Date.now() for (var i in matrix) { for (var j in matrix[i]) { if (matrix[i][j] = 1) { end = Date.now() - start } } } return end } function test_for_of(matrix) { let start = null let end = null start = Date.now() for (var arr of matrix) { for (var val of arr) { if (val = 1) { end = Date.now() - start } } } return end } function test_for(matrix) { let start = null let end = null start = Date.now() for (var i = 0; i < matrix.length; i++) { for (var j = 0; j < matrix[i].length; j++) { if (matrix[i][j] = 1) { end = Date.now() - start } } } return end } }) 2.4 персонально для @yar85 объект и массив помещённые в массив являются ссылками, операция delete и присвоения undefined удаляет только ссылку из массива. такие объекты удаляются из памяти в случае, а об этом читаем тут learn.javascript.ru/memory-management { let o = { 'ссылка на объект'() { let arr = [] let o = { name: 'O' } arr.push(o) // delete arr[0] // log(()=>f) // () => o {name: "O"} // arr[0] = undefined // log(()=>f) // () => o {name: "O"} log(() => o) }, 'ссылка на массив'() { let arr = [] let arr2 = ['arr2'] arr.push(arr2) // delete arr[0] // log(()=>f) // () => arr2 ["arr2"] // arr[0] = undefined // log(()=>f) // () => arr2 ["arr2"] log(() => arr2) }, } Object.values(o).forEach(group) } 2.5 Оператор расширения (spread) group(function spread() { let arr = [,,,'C'] let arr2 = [...arr] log(() => arr2) // (4) [undefined, undefined, undefined, "C"] })