Страницы

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

Показаны сообщения с ярлыком область-видимости. Показать все сообщения
Показаны сообщения с ярлыком область-видимости. Показать все сообщения

среда, 5 февраля 2020 г.

Контекст в JS (this) [дубликат]

#javascript #функции #область_видимости


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            Потеря контекста вызова
                                
                                    (5 ответов)
                                
                        
                                Закрыт 2 года назад.
            
                    
Правильно ли я понимаю, что в этом коде в 1-м варианте так как у стрелочных функций
нету this она берет this у "родителя" , а во 2-м варианте this вообще нету поэтому
будет ошибка?



const user = {
  name: 'Bob',
  city: ["Madrid", 'Rome', 'LA'],
  printLocation: function() {
    this.city.forEach(city => {
      console.log(`${this.name} live in ${city}`)
    })
  }
}

user.printLocation()

const user2 = {
  name: 'Bred',
  city: ["Madrid", 'Rome', 'LA'],
  printLocation: () => {
    this.city.forEach(city => {
      console.log(`${this.name} live in ${city}`)
    })
  }
}

user2.printLocation()



    


Ответы

Ответ 1



а во 2м варианте this вообще нету this есть, но в данном случае ссылается он на объект window. В стрелочных функциях, this подхватывает значение лексического контекста. Если простым словами, то значение this внутри стрелочной функции, будет таким же, как и снаружи. Однако, в ES6 появились именно методы объекта и для более короткого синтаксиса, можете использовать их: const user = { name: 'Bred', city: ["Madrid", 'Rome', 'LA'], printLocation() { this.city.forEach(city => { console.log(`${this.name} live in ${city}`); }); } }; user.printLocation();

Ответ 2



const user = { name: 'Bob', city: ["Madrid", 'Rome', 'LA'], printLocation: function() { this.city.forEach(city => { console.log(`${this.name} live in ${city}`) }) } } user.printLocation() const user2 = { name: 'Bred', city: ["Madrid", 'Rome', 'LA'], printLocation: () => { user2.city.forEach(city => { console.log(`${user2.name} live in ${city}`) }); } } user2.printLocation()

пятница, 31 января 2020 г.

Необычное поведение области видимости: изменяемый аргумент по умолчанию [дубликат]

#python #область_видимости


        
             
                
                    
                        
                            На этот вопрос уже дан ответ здесь:
                            
                        
                    
                
                        
                            python mutable default параметры [дубликат]
                                
                                    (1 ответ)
                                
                        
                                Закрыт 2 года назад.
            
                    
Столкнулся с одной особенностью Python'а не могу найти материал по этой теме, подскажите
почему так происходит 

def foo(lst = []):
    lst.append(1)

    return lst

foo()
foo()
lst = foo()

print(lst)


Вывод

[1, 1, 1]

    


Ответы

Ответ 1



Инициализация аргументов по-умолчанию происходит 1 раз - до вызова функции. lst = [] - тут создается список, который используется для всех последующих вызовов функции, т.е. вызывая функцию без аргумента, вы всегда работаете с одним и тем же объектом. l = foo() k = foo() id(l) == id(k) # True l is k # True

Ответ 2



Из-за того, что в Python аргументы с значением по умолчанию вычисляются единожды в момент объявления функции, для примера с изменяемыми объектами (например, контейнерами типа list, dict, set, и т.п.) нужно так оформлять: def foo(lst=None): if lst is None: lst = [] lst.append(1) return lst foo() foo() lst = foo() print(lst) # [1] my_list = [0] lst = foo(my_list) print(lst) # [0, 1] Такая фигня не коснется неизменяемых объектов (типа чисел, строк и т.п.), так что смело можно их использовать: def foo(lst=None, value=1): if lst is None: lst = list() lst.append(value) return lst

Ответ 3



в Python аргументы по умолчанию вычисляются единожды в момент объявления функции,а не при вызове функции( как например это сделано в руби)

суббота, 28 декабря 2019 г.

Случаи указания типа данных в условии цикла

#cpp #циклы #область_видимости


Добрый вечер. Пришел с вопросом. Читал тут книгу, в одном фрагменте было написано,
 что если я укажу тип данных у переменной в условии функции, то значение переменной
будет иметь большую область видимости, чем если бы я указал переменную без типа. То
есть без типа переменная будет действовать, пока активен цикл, но с типом данных она
будет действовать и на еще одни скобки.

Решил проверить. Написал с int'ом-все сработало. Убрал int-и программа стала использовать
значение переменной в цикле во всей программе и по какому-то принципу компилятор его
даже изменил, по какому-я не понимаю.

Вопрос: Я некорректно понял инфу из учебника? Да, то как все должно быть на самом деле?

#include 
using namespace std;

int main() {
 int done=5;
 int howmany=3;

   for( done=1; done


Ответы

Ответ 1



Рассмотрим следующую программу #include int main() { int done = 5; int howmany = 3; for ( done = 1; done < howmany; done++ ) { std::cout << done << std::endl; } std::cout << done << std::endl; return 0; } Ее вывод на консоль 1 2 3 В этой программе в блоке кода функции main объявлена переменная done. Сначала эта переменная инициализируется значением 5 int done = 5; а затем в предложении for ей присваивается значение 1 for ( done = 1; done < howmany; done++ ) ^^^^^^^^ После выхода из цикла эта переменная будет иметь значение 3. Теперь рассмотрим следующую программу #include int main() { int done = 5; int howmany = 3; for ( int done = 1; done < howmany; done++ ) { std::cout << done << std::endl; } std::cout << done << std::endl; return 0; } Ее вывод на консоль 1 2 5 В этой программе в предложении for объявляется переменная с именем done, совпадающем с именем переменной, объявленной в блоке кода main. for ( int done = 1; done < howmany; done++ ) ^^^^^^^^^^^^ Эта переменная в предложении for скрывает одноименную переменную с таким же именем, объявленную во внешнем блоке кода. Ее область определения - это тело цикла for. После выхода из цикла данная переменная прекращает свое существование. Из стандарта C++ (6.5.3 The for statement) 3 If the for-init-statement is a declaration, the scope of the name(s) declared extends to the end of the for statement. Поэтому последняя строка вывода программы 5 уже выводит на консоль значение переменной done, которая была объявлена до цикла в блоке кода функции main В общем случае имя, объявленное во внутренней области объявления скрывает такое же имя, объявленное во внешней области объявления Из стандарта C++ (3.3.10 Name hiding) 1 A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2). Обратите внимание, что есть важное отличие в определении предложения for между C++ и C. В C++ во второй части предложения for, где записывается условие, также может быть объявление. Рассмотрите следующую демонстрационную программу #include int main() { int done = 5; int howmany = 3; for ( ; int howmany = done; done-- ) { std::cout << done << std::endl; } std::cout << '\n' << howmany << std::endl; return 0; } Ее вывод на консоль 5 4 3 2 1 3 При каждой итерации данного цикла for for ( ; int howmany = done; done-- ) ^^^^^^^^^^^^^^^^^^ объявляется переменная howmany, которая скрывает переменную с таким же именем, объявленную в функции main. Значение, присвоенное этой переменной, преобразуется к булевскому типу. Если оно равно 0, то условие будет ложным и произойдет выход из цикла. После цикла выводится уже значение переменной howmany, объявленной в main. Ну, и напоследок пример, когда в предложении for сразу в двух его частях объявляются переменные, которые скрывают одноименные переменные с теми же именами, объявленные в main. После выхода из цикла эти переменные прекращают свое существование, и становятся видимыми переменные, объявленные в main. #include int main() { int done = 10; int howmany = 20; for ( int done = 5; int howmany = done; done-- ) { std::cout << done << std::endl; } std::cout << '\n' << done << std::endl; std::cout << howmany << std::endl; return 0; } Вывод этой программы на консоль 5 4 3 2 1 10 20 Предложение for в этой программе логически может быть представлено как { int done = 5; Label_repeat: { int howmany = done; if ( howmany != 0 ) { std::cout << done << std::endl; done--; goto Label_repeat; } else { goto Label_exit; } } } Label_exit: //...

Ответ 2



Как я понимаю, вы просто указали в цикле for for(int done .... При этом произошло следующее: вы объявили новую переменную done, которая имеет областью видимости только цикл for, а после выхода из него это переменная done благополучно умирает, и имя done относится вновь к той переменной, которая объявлена в начале функции main. Поскольку в цикле вы меняли переменную, которая просто "тезка" локальной переменной done из функции main, последняя оставалась неизменной. Но как только вы убираете слово int из заголовка цикла for, объявление исчезает, и переменная, используемая в цикле for - та же, что объявлена в main. Естественно, что при работе цикла она изменяется. А вообще по вопросу очевидно, что вы эту тему понимаете неверно, так что почитайте повнимательнее учебник на тему областей видимости переменных.

воскресенье, 8 декабря 2019 г.

Почему глобальные переменные это зло, а поля класса нет?

#ооп #область_видимости


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


Ответы

Ответ 1



Глобальные переменные в большинстве случаев нарушают инкапсуляцию. К ним открыт неконтролируемый доступ отовсюду. В большом проекте при обилии глобальных переменных возникает путаница в именах. Глобальную переменную же видно отовсюду, надо, чтобы отовсюду было понятно, зачем она. Глобальные переменные в большинстве случаев нарушают принцип инверсии зависимостей (или делают возможным его нарушение). Глобальные переменные ухудшают масштабируемость проекта. Глобальные переменные ухудшают читаемость кода (в каком-то конкретно взятом месте непонятно, нужна ли какая-то конкретная глобальная переменная, или нет). Глобальные переменные приводят к трудноуловимым ошибкам. Примеры: нежелательное изменение её значения в другом месте/другим потоком, ошибочное использование глобальной переменной для промежуточных вычислений из-за совпадения имен, возвращение функцией неправильного значения при тех же параметрах (оказывается, она зависима от глобальной переменной, а ее кто-то поменял). Глобальные переменные создают большие сложности при использовании модульного тестирования. Глобальные переменные увеличивают число прямых и косвенных связей в системе, делая её поведение труднопредсказуемым, а её саму - сложной для понимания и развития. Поля - это такие же глобальные переменные, только в пределах класса. А давайте одежду дома складывать прямо на пол в любом месте квартиры: ведь 30 кв. см ящика в комоде - это те же 30 кв. см поверхности, что и на полу, только в пределах ящика. И гаражи для машин не нужны, можно на улице ставить. Надеюсь, аналогия понятна. Ключевая ошибка в утверждении автора заключается в том, что поля класса никаким образом не являются глобальными - они принадлежат объекту (экземпляру) класса, если они не статические. У одного объекта - одни значения, у другого - другие. А статические поля класса общие для всех экземпляров, и это чаще всего тоже не очень хорошо.

понедельник, 15 июля 2019 г.

как остановить CountDownTimer при нажатии клавиши ввод на клавиатуре

Есть таймер (прописан в OnCreate):
CountDownTimer timer; timer = new CountDownTimer(10000, 1000) { public void onTick(long millisUntilFinished) { text_d1.setText("Осталось: "+ millisUntilFinished / 1000);
public void onFinish() { text_d1.setText("Время вышло"); } }.start();
Есть метод обработки нажатия клавиши ввод на виртуальной клавиатуре:
public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && (keyCode == KeyEvent.KEYCODE_ENTER)) { // тут разные условия, в зависимости от того, в каком edittext нажата клавиша ввод
return true; } return false; }
Логика такая:
Как только открывается активити, таймер запускается.
Таймер автоматически останавливается через 10 сек.
Как добавить условие, что таймер также останавливается, если клавиша ввод на клавиатуре нажата?


Ответ

Скорее всего вам надо просто вызвать timer.cancel() в нужном месте. Но для этого вам надо иметь доступ к переменной timer. А доступ к ней в обработчиках разных можно получить, если она будет объявлена не внутри метода onCreate, а на уровне активити. Т.е., примерно, так:
CountDownTimer timer;
public void onCreate(Bundle b) { ... }

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

Контекст в JS (this) [дубликат]

На данный вопрос уже ответили: Потеря контекста вызова 5 ответов Правильно ли я понимаю, что в этом коде в 1-м варианте так как у стрелочных функций нету this она берет this у "родителя" , а во 2-м варианте this вообще нету поэтому будет ошибка?
const user = { name: 'Bob', city: ["Madrid", 'Rome', 'LA'], printLocation: function() { this.city.forEach(city => { console.log(`${this.name} live in ${city}`) }) } } user.printLocation() const user2 = { name: 'Bred', city: ["Madrid", 'Rome', 'LA'], printLocation: () => { this.city.forEach(city => { console.log(`${this.name} live in ${city}`) }) } } user2.printLocation()


Ответ

а во 2м варианте this вообще нету
this есть, но в данном случае ссылается он на объект window. В стрелочных функциях, this подхватывает значение лексического контекста. Если простым словами, то значение this внутри стрелочной функции, будет таким же, как и снаружи. Однако, в ES6 появились именно методы объекта и для более короткого синтаксиса, можете использовать их:
const user = { name: 'Bred', city: ["Madrid", 'Rome', 'LA'], printLocation() { this.city.forEach(city => { console.log(`${this.name} live in ${city}`); }); } }; user.printLocation();

пятница, 7 декабря 2018 г.

Случаи указания типа данных в условии цикла

Добрый вечер. Пришел с вопросом. Читал тут книгу, в одном фрагменте было написано, что если я укажу тип данных у переменной в условии функции, то значение переменной будет иметь большую область видимости, чем если бы я указал переменную без типа. То есть без типа переменная будет действовать, пока активен цикл, но с типом данных она будет действовать и на еще одни скобки.
Решил проверить. Написал с int'ом-все сработало. Убрал int-и программа стала использовать значение переменной в цикле во всей программе и по какому-то принципу компилятор его даже изменил, по какому-я не понимаю.
Вопрос: Я некорректно понял инфу из учебника? Да, то как все должно быть на самом деле?
#include using namespace std;
int main() { int done=5; int howmany=3;
for( done=1; done cout<Вывод:
7 7 3


Ответ

Рассмотрим следующую программу
#include
int main() { int done = 5; int howmany = 3;
for ( done = 1; done < howmany; done++ ) { std::cout << done << std::endl; }
std::cout << done << std::endl;
return 0; }
Ее вывод на консоль
1 2 3
В этой программе в блоке кода функции main объявлена переменная done. Сначала эта переменная инициализируется значением 5
int done = 5;
а затем в предложении for ей присваивается значение 1
for ( done = 1; done < howmany; done++ ) ^^^^^^^^
После выхода из цикла эта переменная будет иметь значение 3.
Теперь рассмотрим следующую программу
#include
int main() { int done = 5; int howmany = 3;
for ( int done = 1; done < howmany; done++ ) { std::cout << done << std::endl; }
std::cout << done << std::endl;
return 0; }
Ее вывод на консоль
1 2 5
В этой программе в предложении for объявляется переменная с именем done, совпадающем с именем переменной, объявленной в блоке кода main.
for ( int done = 1; done < howmany; done++ ) ^^^^^^^^^^^^
Эта переменная в предложении for скрывает одноименную переменную с таким же именем, объявленную во внешнем блоке кода. Ее область определения - это тело цикла for. После выхода из цикла данная переменная прекращает свое существование.
Из стандарта C++ (6.5.3 The for statement)
3 If the for-init-statement is a declaration, the scope of the name(s) declared extends to the end of the for statement.
Поэтому последняя строка вывода программы
5
уже выводит на консоль значение переменной done, которая была объявлена до цикла в блоке кода функции main
В общем случае имя, объявленное во внутренней области объявления скрывает такое же имя, объявленное во внешней области объявления
Из стандарта C++ (3.3.10 Name hiding)
1 A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).
Обратите внимание, что есть важное отличие в определении предложения for между C++ и C.
В C++ во второй части предложения for, где записывается условие, также может быть объявление.
Рассмотрите следующую демонстрационную программу
#include
int main() { int done = 5; int howmany = 3;
for ( ; int howmany = done; done-- ) { std::cout << done << std::endl; }
std::cout << '
' << howmany << std::endl;
return 0; }
Ее вывод на консоль
5 4 3 2 1
3

При каждой итерации данного цикла for
for ( ; int howmany = done; done-- ) ^^^^^^^^^^^^^^^^^^
объявляется переменная howmany, которая скрывает переменную с таким же именем, объявленную в функции main. Значение, присвоенное этой переменной, преобразуется к булевскому типу. Если оно равно 0, то условие будет ложным и произойдет выход из цикла.
После цикла выводится уже значение переменной howmany, объявленной в main
Ну, и напоследок пример, когда в предложении for сразу в двух его частях объявляются переменные, которые скрывают одноименные переменные с теми же именами, объявленные в main. После выхода из цикла эти переменные прекращают свое существование, и становятся видимыми переменные, объявленные в main
#include
int main() { int done = 10; int howmany = 20;
for ( int done = 5; int howmany = done; done-- ) { std::cout << done << std::endl; }
std::cout << '
' << done << std::endl; std::cout << howmany << std::endl;
return 0; }
Вывод этой программы на консоль
5 4 3 2 1
10 20

Предложение for в этой программе логически может быть представлено как
{ int done = 5;
Label_repeat: { int howmany = done;
if ( howmany != 0 ) { std::cout << done << std::endl; done--; goto Label_repeat; } else { goto Label_exit; } } } Label_exit: //...