Страницы

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

понедельник, 13 мая 2019 г.

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

Когда я определяю переменную, одновременно присваивая ей значение, я могу указать класс, наследником которого является результат выражения, могу указать интерфейс, который имплементируется результатом выражени или другой тип, к которому можно неявно привести этот результат. И в этом случае компилятор позволит мне не ошибиться с результатом выражения.
Так же я могу не указывать тип переменной, а предоставить эту возможность компилятору, воспользовавшись ключевым словом var.
var a = 5; // int var b = 5.0; // double
Но когда я определяю константу - компилятор заставляет меня прописать тип константы в явном виде.
const int c = 5; const double d = 5.0;
С чем связана такая непоследовательность? Неужели тип константы определить сложнее, чем тип переменной?


Ответ

Eric Lippert, ведущий разработчик компилятора C# отвечал на этот вопрос: https://stackoverflow.com/a/2128581/1159507
Если вкратце то var предназначена для упрощения конструкция типа Dictionary> priceTable = new Dictionary>();
var от слова variable - переменная, В то же время ключевое слово const подчеркивает что что значение меняться не может, поэтому ограничение компилятора тот исключительно логическое, чтоб не было нонсенса типа const var

Передача двумерного массива в функцию (Rust)

Кто-нибудь может подсказать, как передать в функцию двумерный массив?
Желательно по ссылке, т.е. без копирования самого массива. К сожалению их "книга" пока не богата на примеры передачи параметров в функцию. Вот как я себе это пытался представить:
fn foo(a:&[&[f64]],x:&[f64]) { for i in 0..3 { for j in 0..4 { println!("{}",a[i][j]); } } }
fn main() { let A:[[f64;4];3]=[[1.1,-0.2, 0.1,1.6], [0.1,-1.2,-0.2,2.3], [0.2,-0.1, 1.1,1.5]]; let mut X:[f64;3]=[0.0;3];
foo(&A,&X); }
"X" передается без проблем, а вот на "А" ругается при всех комбинациях [ ] и &, которые я смог придумать:
src/main.rs:16:6: 16:8 error: mismatched types: expected `&[&[f64]]`, found `&[[f64; 4]; 3]` (expected slice, found array of 3 elements) [E0308] src/main.rs:16 foo(&A,&X); ^~ error: aborting due to previous error Could not compile `example`.


Ответ

Дело в том, что, к примеру, выражение [1i32, 2, 3] возвращает тип [i32; 3] — массив с заданной при компляции длиной. Когда же &[f64] является срезом — ссылочным типом, состоящим из указателя на массив и длины (известной во время выполнения).
Вот так будет работать:
fn foo(a:&[&[f64]],x:&[f64]) { for i in 0..3 { for j in 0..4 { println!("{}",a[i][j]); } } }
fn main() { let a:[&[f64];3]=[&[1.1,-0.2, 0.1,1.6], &[0.1,-1.2,-0.2,2.3], &[0.2,-0.1, 1.1,1.5]]; let x:[f64;3]=[0.0;3];
foo(&a,&x); }
К сожалению их "книга" пока не богата на примеры передачи параметров в функцию.
Кроме собственно официальной документации по Rust существует очень хорошее руководство с множеством прекрасных примеров Rust by Example

Класс устанавливающий курсор ожидания и автоматически сбрасывающий его

Создал вот такой класс:
class CursorEx: IDisposable { public CursorEx() { Cursor.Current = Cursors.WaitCursor; } public void Dispose() { Cursor.Current = Cursors.Default; } }
Использую вот так:
public void Method() { new CursorEx(); //Здаесь что-то выполняется }
Подразумевается, что после выполнения метода, вызовется метод Dispose() и курсор установится на дефолтный. Могут ли быть какие-то варианты, когда произойдет сбой?


Ответ

Во-первых, вы забыли вызвать Dispose. Для этого следует использовать using
using (new CursorEx()) { // что-то выполняется }
На сборку мусора полагаться нельзя, она вызывается недетерминированно в любой момент после пропадания объекта из области видимости.
Во-вторых, вы не восстанавливаете исходный курсор. Если какая-то функция изменяет курсор, а затем вызывает функцию, которая тоже изменяет курсор, то курсор будет восстановлен уже после возврата из первой функции:
using (new CursorEx()) { using (new CursorEx()) { // что-то выполняется } // курсор уже восстановлен } // курсор должен был быть восстановлен здесь
Вам следует сохранять текущий курсор в конструкторе и восстанавливать его в Dispose
В-третьих, можно избавиться от лишнего объекта в памяти, если заменить класс на структуру.
Итого:
public struct CursorWaiter : IDisposable { private readonly Cursor _originalCursor;
public CursorWaiter (Cursor newCursor = null) { _originalCursor = Cursor.Current; Cursor.Current = newCursor ?? Cursors.WaitCursor; }
public void Dispose () { Cursor.Current = _originalCursor; } }
Из комментариев: этот код рассчитан на то, что программист будет использовать тип только с помощью using, не будет уничтожать объект по несколько раз, не будет копировать и т.п. Если есть сомнения в этом, то нужно добавить проверку на повторный вызов Dispose (с помощью отдельного флага или обнуления _originalCursor), а также заменить класс на структуру для избавления он возможности копирования или вовсе скрыть тип за методом с лямбдой.

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

Вот такая ситуация: падает приложение с ошибкой outOfMemoryError. Хочу отловить это событие и хочу, чтобы когда это случилось, JVM создал HPROF файл. Как запустить приложение на устройстве с определенными JVM флагами? Обычно это делалось просто -XX:HeapDumpOnOutOfMemoryError. Или может есть какие-то встроенные удобные тулзы в Android Studio? Потому что я хочу запихнуть этот HPROF файл в MemoryAnalyzer. Но, может, этот метод уже устарел?


Ответ

HeapDumpOnOutOfMemoryError это флаг Oracle VM, в Dalvik и ART его нет.
В общем нужно или вручную создавать HPROF или если скажем проблема у заказчика - натыкать запись в лог состояние памяти по всему коду.
Ну и перехватывать OOMe тоже можно, только ловить не Exception a Error, в try-cach или глобально.
См. также видео с Google IO на эту тему - https://www.youtube.com/watch?v=_CruQY55HOk

Медленное сокрытие action bar

Использую toolbar и надо сделать медленное скрытие и так же раскрытие, при использовании actionBar.hide() она резко появляется и так же резко исчезает


Ответ

Нужно использовать анимацию.
Пример
toolbar.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();

Что должно попадать в коммит?

Я пользуюсь Eclipse и Egit для работы с Git. Каждый раз, когда я делаю коммит, мне предлагается выбрать из файлов которые нужно закоммитить. Часть файлов уже выбраны, а часть нет. Из выбранных файлов мне Eclipse обычно предлагает закоммитить все измененные java файлы а также некоторые class файлы и некоторые другие. Насколько я понимаю class файлы генерируются автоматически и по идее их коммитить не обязательно так же как и jar файлы. Но Eclipse мне регулярно предлагает их включать в коммит.
Подскажите как поступать в этом случае? Надо ли включать в коммит файлы с расширением class, jar и другие?


Ответ

Если для соответствующего class файла у вас есть java файл, то включать class файл нет никакого смысла. Другое дело, что иногда у Вас есть только class файл, тогда наверное его стоит включить. Аналогично и с jar файлами. Если этот jar - продукт компиляции Вашего кода - нет смысла его включать. Если это сторонняя библиотека - возможно есть, а может проще просто правильно настроить maven/gradle, что бы он сам все умел вытянуть.
Что бы git не предлагал включать ненужные файлы, их нужно добавить в список исключений - в файл .gitignore
В целом, в коммиты нужно включать то, что нужно для компиляции. Сторонний человек должен спулить репозиторий, открыть его в эклипсе и просто нажать "скомпилируй".

Как выбрать N значений по N ключам из одной и той же таблицы-справочника без нескольких LEFT JOIN?

Есть две таблицы:
1.Справочник ref:
+-----+-----------+ | id | text | |-----+-----------+ | 1 | однажды | | 2 | в | | 3 | студеную | | 4 | зимнюю | | 5 | пору | +-----+-----------+
2.Данные main:
+------+------+------+------+-----+ | fk1 | fk2 | fk3 | fk4 | fk5 | +------+------+------+------+-----+ | 1 | 2 | 3 | 4 | 5 | +------+------+------+------+-----+
Чтобы получить строчку текста из записи во второй таблице, где хранятся только коды слов можно сделать так
SELECT table1.text as word1, table2.text as word2, table3.text as word3, table4.text as word4, table5.text as word5 FROM main left join ref as table1 on (fk1=table1.id) left join ref as table2 on (fk2=table2.id) left join ref as table3 on (fk3=table3.id) left join ref as table4 on (fk4=table4.id) left join ref as table5 on (fk5=table5.id);
И получить ['однажды', 'в', 'студеную', 'зимнюю', 'пору']
Но это не кажется очень правильным в моих условиях, где есть таблица объявлений main с несколькими полями-ключами (marked_text_fk, main_text_fk), которые связаны с таблицей "текстовок" (text_id, text_fulltext), потому что количество записей - 1 млн в первой таблице и 0.5 млн во второй.
Пожалуйста, подскажите есть ли другие варианты запроса или разбивки данных на таблицы с такими исходными условиями?


Ответ

Пятикратный join - вполне нормальное решение данной задачи в такой формулировке. (Кстати, почему вы делаете left join? Данные в таблицах что, могут быть несогласованны?)
Тут, на самом деле, странной выглядит сама схема БД. Почему в таблице main хранится пять ссылок одного типа? Их точно никогда не придется хранить шесть штук или четыре? Стоило бы сделать промежуточную таблицу-связку между main и ref, с полями mainid, refid и order (1 и 3е поля входят в первичный ключ).