Останні відповіді

  1. В perl6 це можна зробити ось так

    perl6 -e 'print(%*ENV<SHELL>,"\n")'
    

  2. Це можна обійти якщо виконати команду:

    $ sudo apparmor_parser -r /etc/apparmor.d/*snap-confine*
    

    Це зробить запуск snap-confine "обмеженим" і snap програми будуть запускатися. Якщо помилка виникне знову, цю команду необхідно буде виконати повторно.


  3. Питання тут, скоріше, в тому, як читати проголошення функцій (та змінних) в C. Історично склалося, що це дещо заплутано. Базове правило: читаємо від ідентифікатора, який визначається, спершу в дужках, потім праворуч, потім ліворуч; але групи ключових слів читаються разом зліва направо. Отже,

    const double * f1(const double ar[], int n);
    

    f1 - це функція, що приймає (список параметрів const double ar[], int n) - далі праворуч нема куди, читаєм ліворуч - яка повертає * - вказівник на const double.

    const double * (* func_ptr)(const double *, int);
    

    func_ptr - це:

    * - вказівник на

    (const double *, int) - функцію, що приймає параметри такого типу

    * - і повертає вказівник на

    const double

    int *ptr_array[10];
    

    ptr_array - це масив вказівників на int.

    int (*ptr_to_array)[10];
    

    ptr_to_array - це вказівник на масив з 10 int-ів.

    int (*func_array[10])(int x);
    

    func_array - це

    [10] - масив з 10

    * - вказівників на

    (int x) - функції, що приймають int

    int - і повертають int.

    int(*(*func_array1[10])(int x))(int);
    

    func_array1 - це

    [10] - масив з 10

    * - вказівників на

    (int x) - функції, що приймають int

    * - і повертають вказівник

    (int) - на функцію, що приймає int

    int - і повертає int.

    Через ці всі складнощі наполегливо раджу все, складніше за дві базові конструкції, проголошувати окремими типами за допомогою typedef або (в C++) using:

    typedef int (*IntFunc)(int x);
    

    IntFunc - це вказівник на функцію, що приймає int та повертає int

    IntFunc func_array[10];
    typedef IntFunc IntFuncGetter(int);
    IntFuncGetter func_array1[10];
    

    func_array та func_array1 визначені так само, як і раніше, але значно читаніше.

    Якщо ви зуміли дочитати до цього місця, то, гадаю, вам уже не буде проблемою прочитати визначення функцій у питанні.


  4. Функція описується так:

    тип_що_повертається им'я_функції([тип1 аргумент1 [, тип2 аргумент2] ...)
    

    Так що

    const double * f2(const double * ar, int n);
    

    const double * - тип який повертається, f2 - ім'я функції, const double * - тип першого аргументу ar, int- тип другого аргументу n.

    Так зрозуміліше?

    На друге питання - "прототип" і визначення повинні збігатися (крім, хіба що, імен аргументів), так що * потрібна точно так же, щоб вказувати тип який повертається.

    Покажчик на функцію даного типу буде мати вигляд

    const double * (* func_ptr)(const double *, int);
    

  5. Виконайте наступне:

    grep -rnw '/path/to/somewhere/' -e 'pattern'
    
    • -r або -R - рекурсивний пошук,
    • -n - вивести номер рядка
    • -w пошук цілого слова.
    • -l (нижній регістр L) можна додати, щоб просто вказати ім'я відповідного файлу.

    Також можна використовувати, --exclude, --include, --exclude-dir. Ці прапори можуть бути використані для ефективного пошуку:

    Ця команда буде здійснювати пошук лише у тих файлах з розширенням .c або .h:

    grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
    

    Ця команда виконає пошук у всіх файлах, за виключенням тих що закінчуються розширенням .o:

    grep --exclude=\*.o -rnw '/path/to/somewhere/' -e "pattern"
    

    Для каталогів можна виключити один або кілька каталогів за допомогою параметра --exclude-dir. Наприклад, ця команда виключить директорії dir1/, dir2/ а також ті що відповідають *.dst/:

    grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/somewhere/' -e "pattern"
    

    Для отримання додаткових опцій перевірте man grep.


  6. Нехай ви хочете склеїти останні три коміти (для 13-ти комітів процес виглядає аналогічно). Для цього є відмінний метод з використанням git rebase. Ця команда дозволяє змінювати історію комітів. Алгоритм роботи виглядає наступним чином:

    1. Зробіть резервну копію. Це зовсім не обов'язково, але допоможе зберегти нервові клітини, якщо щось піде не так. варіанти:
    • Копія каталогу з файлами в якому розгорнуто git репозиторій.
    • git branch backup або git tag backup в останньому коміті.
    • Прочитати довідку по командам reflog і reset і перевірити, що бекапи вже є.
    1. Позбавтеся від незакомічених змін ( git add + git commit або git stash або щось ще).
    2. Виконайте git rebase -i HEAD~3. У відповідь на це ви отримаєте "діалог" (вікно редагування файлу) виду:
    pick bcdca61 Second commit
    pick 4643a5f The third commit with cool stuff
    pick e0ca8b9 The last commit
    
     #  Rebase 48411de..e0ca8b9 onto 48411de
     #
     #  Commands:
     #  p, pick = use commit
     #  r, reword = use commit, but edit the commit message
     #  e, edit = use commit, but stop for amending
     #  s, squash = use commit, but meld into previous commit
     #  f, fixup = like "squash", but discard this commit's log message
     #  x, exec = run command (the rest of the line) using shell
    

    при цьому, коміти вказані в порядку зростання часу створення (найнижчий - найсвіжіший).

    1. В "діалозі" з вам потрібно замінити pick на squash для двох найсвіжіших комітів (два нижні рядки). В наведеному вище прикладі, це повинно виглядати ось так:
    pick bcdca61 Second commit
    squash 4643a5f The third commit with cool stuff
    squash e0ca8b9 The last commit
    
     #  Rebase 48411de..e0ca8b9 onto 48411de
     #
     #...
    

    Після цього ви повинні закрити цей "діалог" (зберегти редагований файл). Якщо для роботи з git використовується vi (за замовчуванням), то це робиться послідовним натисканням ESC, введенням :wq і натисненням Enter.

    1. У наступному "діалозі" вам запропонують вказати заголовок для отриманого коміту.

  7. У PHP починаючи з версії 5.4.0 з'явився прапор JSON_UNESCAPED_UNICODEі все стало набагато простіше:

    json_encode($array, JSON_UNESCAPED_UNICODE);
    

  8. Проблема лежить в області забезпечення зворотної сумісності.

    Подивіться, будь-яку новий мову програмування - наприклад Паскаль, не кажучи вже про Java або C # - не потребують заголовних файлах. Без сумніву, C++ теж міг би обійтися без них. У чому ж справа?

    Перенесемося на півстоліття назад, в 1972 рік. Уявімо собі компілятор мови C.

    Припустимо, ми хочемо написати дизайн компілятора. Ми не можемо скомпілювати всю програму за раз, у нас на це просто не вистачить пам'яті. Комп'ютери тоді були маленькими і повільними. Ми хочемо компілювати програму по шматочках, по кілька функцій за раз.

    У нас відразу ж виникає проблема: як скомпілювати функцію f, яка посилається на іншу функцію g? Нам потрібно окремий опис інших функцій. Ми могли б, звичайно, прочитати всі вихідні файли, для початку з'ясувати, які функції у нас є, і потім прочитати їх вдруге і скомпілювати один за одним. Але це було занадто складно і повільно, потрібно було парсити визначення функцій двічі, і один раз викидати результат! Це неприпустима витрата процесорного часу! Плюс, якщо тримати в пам'яті визначення всіх функцій, може знову-таки не вистачити пам'яті.

    На кого Денніс вирішив покласти складну проблему відділення опису функції від її реалізації, і підключення тільки потрібних описів при компіляції даної функції? На нас, програмістів. Він вирішив, що ми повинні самі допомогти компілятору і скопіювати визначення функцій в окремий файл, і самі вказати компілятору, які файли з визначеннями потрібні. (Тобто перший крок компіляції покладається на нас.)

    Це радикально спростило компілятор, але привело в свою чергу до проблем. Що буде, якщо ми забули підключити потрібні заголовки? Відповідь: помилка компіляції. Що буде, якщо зміст тексту заголовки змінюється в залежності від якого-небудь макросу? Відповідь: компілятор «тупий», і не намагається детектувати цю проблему, він перекладає відповідальність на нас.

    На момент розробки мови це було правильне рішення. Компілятор виявився практичним, швидким, і програмісти були не проти допомогти компіляції. Ну і якщо хто припускався помилки, сам був винен.

    Перемотати стрілки годинника в 1983 рік. Бьярн створює C++. Він вирішив злетіти на хвилі популярності мови C, і перейняв модель компіляції C з окремими translation unit'ами та пов'язаними з цим проблемами прямо з C. Втім, перші версії C++ були просто препроцесором мови C! Тому проблеми роздільної компіляції перекочували з C в C++. Більше того, додалися нові проблеми. Наприклад, шаблони класів виглядають як класи, але не генерують об'єктного коду самі по собі, тому для них доводиться йти на хитрощі і обходити недоліки системи роздільної компіляції (наприклад, включенням реалізації в header і трюками компоновщика).

    А далі вступила в гру зворотна сумісність. Зараз, в 2017 році, ми маємо так багато коду, написаного в стилі «з заголовками», і так багато коду виходить з різних тонкощів, пов'язаних з цим, що міняти парадигму вже пізно, поїзд практично поїхав.

    Втім, існує проект модульної системи в C++, який повинен допомогти програмістам позбутися спадщини півстолітньої давності. Він ще не реалізований, і в ньому є складнощі рівня дизайну (наприклад, в header'і був визначений макрос, чи буде його видно, якщо ми перейдемо від header'ів до модулів?) Сподіваюся, в майбутньому розробники мови таки зможуть побороти проблему зворотної сумісності.


  9. import itertools
    
    x, y, z = 2, 4, 12
    
    for num in itertools.permutations([x, y, z]):
        print(num)
    		```
    

  10. Поки що так. Відвідувачів на сайті ще не дуже багато, треба з чогось починати :)


  11. Якщо у вас є можливість, скористайтеся функцією _.split(), наданою lodash. Починаючи з версії 4.0, _.split() може розділяти смайлики Unicode.

    Використання рідного методу .reverse().join('') для зворотного виводу символів має чудово працювати зі смайлами

    function reverse(txt) { return _.split(txt, '').reverse().join(''); }
    const text = 'Hello world👩‍🦰👩‍👩‍👦‍👦';
    console.log(reverse(text));
    

  12. Це можна зробити так:

    list_3 = [ f'{i}-{j}' for i, j in zip(list_1, list_2) ]
    

    або так

    list_3 = [*map(lambda x: f'{x[0]}-{x[1]}', zip(list_1, list_2))]
    

    або так

    list_3 = [*map(lambda x: '-'.join(x), zip(list_1, list_2))]
    

    або так

    list_3 = [*map(lambda x, y: f'{x}-{y}', list_1, list_2)]
    

    або так

    list_3 = [*map('{}-{}'.format, list_1, list_2)]
    

    або так (поки що найкоротший запис)

    list_3 = [*map('-'.join, zip(list_1, list_2))]