Страницы

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

суббота, 13 октября 2018 г.

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

Кто-то может расстолковать какая разница:

Merge Rebase Branch Default
И
Using Stash Using Shelve
Что в каких случаях используется?


Ответ

Для начала git stash или git shelve. Когда Вы подтягиваете новые изменения, в Вашем рабочем каталоге могут быть измененные (незакоммиченные) файлы. Естественно, что эти файлы при слиянии изменений могут потерятся. Поэтому гит предлагает их "спрятать в карман". Это называется git stash. После того, как новый код будет получен с удаленного репозитория, изменения с stash можно накатить назад (естественн, при этом возможно нужно будет решить конфликты). В "кармане" можно хранить сколько угодно изменений (логично - ограничены своим диском) и карман не передается на сервер. Детальнее о git stash на русском.
git shelve - это древний проект (2008 года), который не поддерживается на данный момент. Как и git shash, умеет прятатть изменения, только в отдельные ветки. Зачем оно в студии - не ведомо.
Теперь о первой колонке. При накатывании чужих коммитов может произойти две ситуации - в ветке есть Ваши коммиты и чужие и когда есть только с одной стороны. Понятно, что когда есть только коммиты одной стороны, то принять изменения очень просто - их нужно просто "скопировать себе" и поправить указатели на ветки.
В том случае, если есть и свои коммиты и чужие, нужно их "сложить вместе". Для этого есть две технологии - merge и rebase. При merge происходит слияние файлов. Там, где файлы одинаковые, проблем нет, там где файлы разные, гит пытается сложить вместе. Иногда у него это не выходит и он просит пользователя "разрешить конфликт" - так как только программист знает, что он хочет.
Но есть второй способ - это rebase. Некоторые люди любят этот способ, а некоторые под страхом разрушить репозиторий боятся его использовать. Работает он очень просто. Сравниваются две ветки и ищется общий предок-коммит. Дальше, с локальной ветки откатываются все коммиты до общего коммита. Естественно, что теперь добавить коммиты с удаленного репозитория просто. После этого локальные коммиты "накатываются поверху". Если в процессе накатки возникают конфликты, их нужно решать.
А вот что такое Branch default - я не знаю, возможно, студия запоминает последний выбор и применяет его.

Почему в C# классы не поддерживают ковариантность и контрвариантность?

Почему только интерфейсы и делегаты в C# поддерживают технику ковариантности и контрвариантности в Generic типах?


Ответ

Хороший вопрос.
Простой, поверхностный ответ — потому что это до сих пор не было имплементировано в языке. Но возникает вопрос, почему это не было имплементировано? Смотрите.
Дел в том, что C# появился как чисто императивный язык, в котором основной тип структур данных — мутабельные (то есть, изменяемые) структуры данных. Теперь представьте себе, что у вас есть класс C. Что вы будете делать с типом T?
Вы не можете иметь метод с входным параметром типа T. Потому что вследствие out у вас может в качестве входного параметра реально прийти тип, базовый для T (по смыслу контравариантности, поэтому-то и используется ключевое слово out: T может встречаться только в «исходящих» позициях, в качестве возвращаемого значения).
То же относится и к публичным свойствам типа T с сеттером (и полям), т. к. это по сути та же функция, принимающая на вход T
Вы не сможете иметь полезное приватное мутабельное поле типа T. Почему? Подумайте, как вы присвоите ему какое-нибудь новое значение. Откуда вы его возьмёте? У вас нету методов, которые принимают на вход T, по описанным причинам, вы можете лишь самостоятельно сконструировать экземпляр. Так что ваше поле типа T будет скорее всего бесполезно.
Без мутабельных полей типа T, много ли будет пользы от такого параметра? Вот поэтому разработчики языка и решили не заморачиваться с поддержкой контравариантности для классов. С ковариантностью по сути та же история, только вместо невозможности записи в поле типа T вы столкнётесь с невозможностью чтения из него: ко- и контравариантность симметричны.

Сейчас язык C# развивается в сторону большей поддержки функционального стиля программирования, в котором популярны иммутабельные (неизменяемые) структуры данных. Если ваша структура данных иммутабельна, вы вполне можете сделать её контравариантной по параметру. Пример лучше всего посмотреть здесь (+T читать как out T). Поэтому стоит рассчитывать, что поддержку вариантности для классов добавят в следующих версиях языка.

Идеи ответа одолжены из ответа Эрика Липперта, разработчика ко- и контравариантности в C#.

Присвоить адрес локальной переменной самой себе

Требуется получить адрес локальной переменной, и сохранить его в эту же переменную. Корректен ли такой код:
void* p = (void*) &p;
GCC переваривает нормально. Возможен ли здесь UB или нарушение strict aliasing?
А также в таком варианте:
int* p = (int*) &p;
ideone


Ответ

Код для void* корректен т.к. тип void** приводится к void*
Код int* p = (int*) &p; сам по себе корректен, т.к. хотя &p имеет тип int**, но его можно привести к int* через reinterpret_cast (C-style cast в данном случае). Однако разыменовывать p нельзя, т.к. это будет нарушением правил alising'а: p фактически указывает на объект с типом int*, а выражение *p трактует этот объект как int
(И конечно же результат такого reinterpret_cast нельзя разыменовать из за правил самого reinterpret_cast, но вопрос был про aliasing.)

Проход по списку std::unique_ptr

Как пройти по списку, содержащему std::unique_ptr, используя следующий синтаксис:
for ( auto i : myList )


Ответ

Смотрите, unique_ptr не копируется (иначе уникальность указателя нарушилась бы). Поэтому вам нужно итерировать не по копиям ваших элементов массива, а по ссылкам на них.
for (auto& i : myList) ...

Javascript: разбить массив на n-ое количество частей

Как на JavaScript можно разбить массив на не более, чем 5 частей в случае разного состава объектов в массиве?
Например, из:
a= [{A:'A'}, {B:'B'}, {C:'C'}, {D:'D'}, {E:'E'}, {F:'F'}, {G:'G'}, {H:'H'}, {I:'I'}];
Получить:
b= [{a:{A:'A'}, b:{B:'B'}}, {c:{C:'C'}, d:{D:'D'}}, {e:{E:'E'}, f:{F:'F'}}, {g:{G:'G'}, h:{H:'H'}}, {i:{I:'I'}}];
P.s. Спасибо за ответы!


Ответ

«Правильный» вариант с reduce() – ведь формально мы из массива получаем какое-то одно значение. Тоже массив, в данном случае.
var a = [{A:'A'}, {B:'B'}, {C:'C'}, {D:'D'}, {E:'E'}, {F:'F'}, {G:'G'}, {H:'H'}, {I:'I'}]; function splitTo( arr, n) { var plen = Math.ceil(arr.length / n); return arr.reduce( function( p, c, i, a) { if(i%plen === 0) p.push({}); p[p.length-1][i] = c; return p; }, []); } var result = splitTo( a, 3); document.body.innerText = JSON.stringify(result);
Нужно знать длину отрезка – округлением в бОльшую сторону деления длины на число отрезков.
Метод массива .reduce() применяет к каждому элементу ф-ю, переданную 1-м параметром, и возвращает одно значение. 2-м параметром даётся начальное значение. Ф-я принимает 4 параметра:
«текущее» значение – сначала оно берётся из «начального значения», а потом оно – то, что вернул предыдущий запуск этой ф-ии с предыдущим элементом массива; очередной элемент из массива; индекс очередного элемента; весь массив, на всякий случай.
Внутри поступаем просто. Если индекс делится на длину отрезка без остатка, то пора дописать в результат пустой объект.
И в любом случае в последний элемент результата дописываем ключём – индекс, а значением очередной элемент массива. Прелесть в том, что не нужно проверять какие-то условия, осталось ли что-то в «хвосте» и т.п. Красота!

Первоначальный вариант ответа, принятый ТС:
Чтобы разделить на 5 (пусть, переменная, parts) частей, надо вычислить, какой длины должны быть части:
len = Math.ceil( a.length / parts); // округлить в бОльшую сторону
И потом идём по элементам, набирая по len элементов, пока не закончатся:
var a = [{A:'A'}, {B:'B'}, {C:'C'}, {D:'D'}, {E:'E'}, {F:'F'}, {G:'G'}, {H:'H'}, {I:'I'}]; var parts = 5; // сколько частей var len = Math.ceil( a.length / parts) ,out = [] ,obj = {} ,i ; for( i=0; i Считаем элементы исходного массива от 0. В объект-заготовку записываем свойством индекс, а значением – очередной элемент исх. массива:
0: {A:'A'} 1: {B:'B'} ..
Пора этот сборный объект записать в результат когда следующим, i+1 индексом, будет кратный длине отрезка, т.е. дающий 0 в остатке от деления. И тогда же, после записи, надо «обнулить» сборный объект для следующей пачки.
Наконец, при выходе из цикла, если в объекте что-то записано, надо этот неполный объект тоже не забыть записать в результат.

Возможно ли в тернарном операторе произвести зависимое от переменной умножение символов

Возможно ли как то упростить код метода:
public String say() { if(i<=0) return name +" спит."; else { StringBuilder sb = new StringBuilder(); for (int j = 0; j < i; j++) { sb.append("я"); } return name + " говорит м"+sb+"у!"; } }
До типа такого:
public String say() { return i<=0?name+" спит.":name + " говорит м"+'я'*i+"у!"; }
Я понимаю, что 'я'*i не правильно. Это образный пример.


Ответ

Вот так, без лишних методов и повторов переменных.
public String sayOrSleep(int i, String name) { return name + ((i<=0) ? " спит." : " говорит м"+ String.format("%0" + i + "d", 0).replace("0","я")+"у!"); }
Зачем писать костыль, когда уже все написано до Вас для подобных случаев :)

Скопировать выделенный текст в буфер обмена?

Как можно скопировать выделенный текст в буфер (например, из строки поиска Google Chrome), чтобы затем сделать Ctrl+V в другое поле?


Ответ

var textarea = document.getElementById("textarea"); var copyButton= document.getElementById("copyButton"); copyButton.addEventListener('click', function(e) { // Выделяем текст в поле textarea.select(); // Копируем текст в буфер обмена document.execCommand('copy'); });