Каково различие между мой и локальный в Perl?

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа прекращает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

63
задан skaffman 13 January 2012 в 10:49
поделиться

12 ответов

Динамический Обзор. Это - аккуратное понятие. Многие люди не используют его или понимают его.

В основном думают my как создание и привязка переменной к одному блоку {}, иначе определяют объем.

my $foo if (true); # $foo lives and dies within the if statement.

Так my переменная - то, к чему Вы привыкли. тогда как с динамическим $var обзора может объявляться где угодно и использоваться где угодно. Таким образом с local Вы в основном приостанавливаете использование той глобальной переменной и используете "локальное значение" для работы с ним. Так local создает временный объем для временной переменной.

$var = 4;
print $var, "\n";
&hello;
print $var, "\n";

# subroutines
sub hello {
     local $var = 10;
     print $var, "\n";
     &gogo; # calling subroutine gogo
     print $var, "\n";
}
sub gogo {
     $var ++;
}

Это должно распечатать:

4
10
11
4
37
ответ дан Venkata Raju 24 November 2019 в 16:11
поделиться

Короткий ответ то, что my метки переменная, столь же частная в лексическом контексте, и local метки переменная как частный в динамическом контексте.

легче понять my, так как это создает локальную переменную в обычном смысле. Существует новая созданная переменная, и это доступно только во включающем лексическом блоке, который обычно отмечается фигурными скобками. Существуют некоторые исключения к правилу курчавой фигурной скобки, такие как:

foreach my $x (@foo) { print "$x\n"; }

, Но это - просто выполнение Perl, что Вы имеете в виду. Обычно у Вас есть что-то вроде этого:

sub Foo {
   my $x = shift;

   print "$x\n";
}

В этом случае, $x является частным к подпрограмме, и ее объем включается фигурными скобками. Вещь отметить, и это - контраст по отношению к local, то, что объем my переменная определяется относительно Вашего кода, как это записано в файле. Это - явление времени компиляции.

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

Это может сбивать с толку сначала, поэтому рассмотреть следующий пример.

sub foo { print "$x\n"; }
sub bar { local $x; $x = 2; foo(); }

$x = 1;
foo(); # prints '1'
bar(); # prints '2' because $x was localed in bar
foo(); # prints '1' again because local from foo is no longer in effect

, Когда foo назван в первый раз, это видит глобальное значение [1 114], который равняется 1. Когда bar назван и local $x выполнения, который переопределяет глобальное $x на стеке. Теперь, когда foo назван от [1 119], это видит новое значение 2 для [1 120]. До сих пор это не является совершенно особым, потому что то же самое произошло бы без вызова с [1 121]. Волшебство состоит в том, что, когда bar возвраты мы выходим, динамический контекст, созданный [1 123] и предыдущее глобальное $x, возвращается в объем. Таким образом для заключительного вызова [1 125], $x 1.

Вы будете почти всегда хотеть использовать my, так как это дает Вам локальную переменную, которую Вы ищете. Очень редко, local действительно удобно, чтобы сделать прохладные вещи.

54
ответ дан chaos 24 November 2019 в 16:11
поделиться

Заключение в кавычки от Изучение Perl:

, Но локальный неверно назван, или по крайней мере обманчиво назван. Наш друг Chip Salzenberg говорит, что, если бы он когда-нибудь получает шанс вернуться в машине времени к 1986 и дать Larry один совет, он сказал бы, что Larry для вызова локальным именем "сохраняет" вместо этого. [14] Поэтому локальный на самом деле сохранит значение выданной глобальной переменной, таким образом, оно будет позже автоматически восстановлено глобальной переменной. (Правильно: эти так называемые "локальные" переменные на самом деле globals!) Этот механизм сохранять-и-восстанавливать - тот же, мы уже видели дважды теперь в контрольной переменной цикла foreach, и в _ массив параметров подпрограммы.

Так, local сохраняет текущее значение глобальной переменной и затем устанавливает его на некоторую форму пустого значения. Вы будете часто видеть, что это раньше хлебало весь файл, вместо того, чтобы вело просто строку:

my $file_content;
{
    local $/;
    open IN, "foo.txt";
    $file_content = <IN>;
} 

Вызов local $/ наборы входной разделитель записей (значение, в котором Perl прекращает читать "строку") к пустому значению, заставляя оператор космического корабля считать весь файл, таким образом, это никогда не поражает входной разделитель записей.

19
ответ дан Drew Stephens 24 November 2019 в 16:11
поделиться

http://perldoc.perl.org/perlsub.html#Private-Variables-via-my ()

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

http://perldoc.perl.org/perlsub.html#Temporary-Values-via-local ()

локальный А изменяет свои перечисленные переменные, чтобы быть "локальным" для блока включения, оценки, или действительно РЕГИСТРИРУЕТ - и любой подпрограмме, названной из того блока. Локальное просто дает временные ценности глобальному (значение пакета) переменные. Это не создает локальную переменную. Это известно как динамический обзор. Лексический обзор сделан с моим, который работает больше как C автоматические объявления.

я не думаю, что это вообще неясно, кроме сказать, что "локальным для блока включения", то, что это означает, - то, что исходное значение восстанавливается, когда из блока выходят.

9
ответ дан Steve Jessop 24 November 2019 в 16:11
поделиться

Я can’t никому не верят, связал с Mark Jason Dominus’ исчерпывающие трактаты по вопросу:

16
ответ дан Aristotle Pagaltzis 24 November 2019 в 16:11
поделиться

Google Well действительно работает на Вас на этом: http://www.perlmonks.org/?node_id=94007

Из ссылки:

Быстрая сводка: 'мой' создает новое переменное, 'локальное' временно исправляет значение переменной.

т.е., 'локальное' временно изменения значение переменной , но [только 113] в объеме это существует в.

Обычно используют мой, это быстрее и не делает ничего довольно странного.

7
ответ дан Eli Courtwright 24 November 2019 в 16:11
поделиться

От man perlsub:

В отличие от динамических переменных, созданных локальным оператором, лексические переменные, объявленные с моим, полностью скрыты от внешнего мира, включая любые названные подпрограммы.

Так, упрощение, my делает Вашу переменную видимой только там, где это объявляется. local делает его видимым вниз стек вызовов также. Вы будете обычно хотеть использовать my вместо local.

6
ответ дан catfood 24 November 2019 в 16:11
поделиться

Ваш беспорядок понятен. Лексический обзор довольно легко понять, но динамический обзор является необычным понятием. Ситуация усугублена именами my и local являющийся несколько неточным (или по крайней мере неинтуитивная) по историческим причинам.

my объявляет лексическую переменную - та, которая видима от точки объявления до конца блока включения (или файл). Это абсолютно независимо от любых других переменных с тем же именем в остальной части программы. Это является частным к тому блоку.

local, с другой стороны, объявляет временное изменение в значении глобальной переменной. Концы изменения в конце объема включения, но переменная - быть глобальным - видимо где угодно в программе.

Как показывает опыт, используйте my, чтобы объявить, что Ваши собственные переменные и local управляют влиянием изменений во встроенных переменных Perl.

Для более полного описания см., что статья Mark Jason Dominus Справляется с Обзором .

4
ответ дан Michael Carman 24 November 2019 в 16:11
поделиться

локальный более старый метод локализации, со времен, когда Perl имел только динамический обзор. Лексический обзор является намного более естественным для программиста и намного более безопасным во многих ситуациях. мои переменные принадлежат объему (блок, пакет или файл), в котором они объявляются.

локальные переменные вместо этого на самом деле принадлежат глобальному пространству имен. Если Вы обращаетесь к переменному $x с локальным, Вы на самом деле обращаетесь к $main:: x, который является глобальной переменной. Вопреки то, что это - имя, подразумевает, все локальные делают продвинуть новое значение на стопку значений за $main:: x до конца этого блока, в котором времени будет восстановлено старое значение. Это - полезная функция в и себя, но это не хороший способ иметь локальные переменные для хоста причин (думайте, что происходит, когда у Вас есть потоки! и думайте, что происходит, когда Вы называете стандартную программу, которая действительно хочет использовать глобальное, которое Вы локализовали!). Однако это был единственный способ иметь переменные, которые были похожи на локальные переменные назад в плохие былые времена перед Perl 5. Мы все еще застреваем с ним.

3
ответ дан skiphoppy 24 November 2019 в 16:11
поделиться

"мои" переменные видимы в текущем блоке кода только. "локальные" переменные также видимы, где когда-либо они были видимы прежде. Например, если Вы говорите "мой $x"; и назовите подфункцию, она не видит тот переменный $x. Но если Вы говорите "локальный $ /"; (к пустому указателю значение разделителя записей) тогда Вы изменяете способ читать из работ файлов в любых функциях, которые Вы вызываете.

На практике, Вы почти всегда хотите "мой", не "локальный".

2
ответ дан andy 24 November 2019 в 16:11
поделиться

примером dinomite использования локального для переопределения рекордного разделителя является единственное время, которое я имею, натыкался в большом программировании жемчуга. Я живу в нишевой среде жемчуга [программирование безопасности], но это действительно - редко используемый объем, по моему опыту.

0
ответ дан phreakre 24 November 2019 в 16:11
поделиться
&s;

sub s()
{
    local $s="5";
    &b;
    print $s;
}

sub b()
{
    $s++;
}

Приведенный выше сценарий печатает 6.

Но если мы изменим local на my, он напечатает 5.

В этом разница. Просто.

0
ответ дан 24 November 2019 в 16:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: