Jump to content

Автовивификация

В Perl языке программирования автовивификация — это автоматическое создание новых массивов и хешей неопределенное значение по мере необходимости каждый раз, когда разыменовывается . Автовивификация Perl позволяет программисту ссылаться на структурированную переменную и произвольные подэлементы этой структурированной переменной без предварительного явного объявления существования переменной и ее полной структуры. [1]

Напротив, другие языки программирования либо: 1) требуют от программиста явного объявления всей структуры переменных перед использованием или ссылкой на любую ее часть; или 2) требовать от программиста объявления части переменной структуры перед обращением к любой ее части; или 3) создать присвоение части переменной перед обращением, присвоением или составлением выражения, которое ссылается на любую ее часть.

Автовивификацию Perl можно сравнить с такими языками, как Python , PHP , Ruby и многими языками стиля C, где разыменование нулевых или неопределенных значений обычно не допускается. [а] Его можно сравнить с «именованным доступом к объекту окна» стандарта HTML. [2] в результате чего соответствующие глобальные переменные автоматически становятся доступными для браузерного JavaScript .

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

  DB<1> x \%h
0  HASH(0x2f1a248)
     empty hash
  DB<2> x $h{1}{2}{3}{4}
0  undef
  DB<3> x \%h
0  HASH(0x2f1a248)
   1 => HASH(0x2f1a260)
      2 => HASH(0x29a3c68)
         3 => HASH(0x2dc3038)
              empty hash
  DB<4>

Приведенный ниже сеанс отладчика иллюстрирует автоматическое оживление хеша при присвоении его внутреннему хешу:

  DB<1> $h{A}{B}{C}{D}=1
  DB<2> x \%h
   0  HASH(0x83c71ac)
   'A' => HASH(0x837d50c)
      'B' => HASH(0x83c71e8)
         'C' => HASH(0x83c7218)
            'D' => 1
  DB<3>

Хэши глубиной в несколько слоев создавались автоматически, без каких-либо объявлений. Автовивификация может предотвратить чрезмерный ввод текста. Если бы Perl не поддерживал автовивификацию, приведенную выше структуру пришлось бы создавать следующим образом:

  DB<1> %h = (A => {B => {C => {D => 1}}})
  DB<2> x \%h
  0  HASH(0x83caba4)
   'A' => HASH(0x83cfc28)
      'B' => HASH(0x83cab74)
         'C' => HASH(0x83b6110)
            'D' => 1
  DB<3>

Дескрипторы файлов и каталогов

[ редактировать ]

Perl 5.6.1 и новее поддерживают автоактивацию дескрипторов файлов и каталогов. [3] Вызов open() для неопределенной переменной будет установлен дескриптор файла. Согласно perl561delta, «[t]his в значительной степени устраняет необходимость в typeglobs при открытии дескрипторов файлов, которые необходимо передавать, как в следующем примере:

for my $file ( qw(this.conf that.conf) ) {
    my $fin = open_or_throw('<', $file);
    process_conf($fin);
    # no close() needed
}
use Carp;
sub open_or_throw {
    my ($mode, $filename) = @_;
    open my $h, $mode, $filename
        or croak "Could not open '$filename': $!";
    return $h;
}

Эмуляция на других языках программирования

[ редактировать ]

Ассоциативные контейнеры стандартной библиотеки C ++ ( std::unordered_map и std::map) использовать operator[] чтобы получить значение, связанное с ключом. Если с этим ключом ничего не связано, он создаст его и инициализирует значение. [4] ценность. Для простых типов, таких как int или float, инициализация значения будет нулевой.

std::unordered_map<std::string, std::vector<int>> a;
a["the answer"].push_back(42); // Autovivifies the a["the answer"] vector and then appends to it.

Другой пример подсчета вхождений строк:

std::unordered_map<std::string, int> counts;
while (auto& s = GetNextString()) {
  counts[s]++; // creates counts[s] if it doesn't exist and set to zero, then increment.
}

Аналогичного трюка можно добиться с помощью insert() метод, который возвращает итератор к элементу, связанному с ключом, даже если он уже существует.

встроенный в Python dict класс может быть подклассом для реализации автоживых словарей, просто переопределив __missing__() метод, который был добавлен в класс в Python v2.5. [5] Существуют и другие способы реализации поведения, [6] [7] но следующий пример — один из самых простых, и экземпляры класса печатаются так же, как и обычные объекты словаря Python.

>>> class Tree(dict):
...     def __missing__(self, key):
...         value = self[key] = type(self)()
...         return value

>>> # Common names by class, order, genus, and type-species
>>> common_names = Tree()
>>> common_names['Mammalia']['Primates']['Homo']['H. sapiens'] = 'human being'
>>> common_names
{'Mammalia': {'Primates': {'Homo': {'H. sapiens': 'human being'}}}}

>>> # Famous quotes by play, act, scene, and page
>>> quotes = Tree()
>>> quotes['Hamlet'][1][3][3] = 'This above all: to thine own self be true.'
>>> quotes
{'Hamlet': {1: {3: {3: 'This above all: to thine own self be true.'}}}}

Хэши Ruby могут принимать блок, определяющий возвращаемый объект для несуществующих индексов. Их можно использовать для реализации автоживущих карт.

irb(main):001:0> tree = proc { Hash.new { |hash, key| hash[key] = tree.call } }
=> #<Proc:0x007fda528749a0@(irb):1>
irb(main):002:0> lupin = tree.call
=> {}
irb(main):003:0> lupin["express"][3] = "stand and deliver"
=> "stand and deliver"
irb(main):004:0> lupin
=> {"express"=>{3=>"stand and deliver"}}

Java Map имеет метод computeIfAbsent[8] который можно использовать для эмуляции автоживущих карт.

public static <K,V> Function<K, V> defaultDict(Map<K, V> map, Supplier<? extends V> supplier) {
    return key -> map.computeIfAbsent(key, k -> supplier.get());
}

public static void main(String[] args) {
    Function<String, List<String>> dict = defaultDict(new HashMap<>(), ArrayList::new);
    dict.apply("foo").add("bar");
}

Массивы PHP изначально являются автоживыми.

$arr = array();
$arr["express"][3] = "stand and deliver";

Однако это относится только к присваиванию, а не к доступу к массиву.

ES6 представляет новый Прокси- класс, который можно использовать для реализации автовивификации. Благодаря другим функциям JavaScript это можно свести к одной строке кода:

var tree = () => new Proxy({}, { get: (target, name) => name in target ? target[name] : target[name] = tree() });

// Test:
var t = tree();
t.first.second.third = 'text';
console.log(t.first.second.third); // or t['first']['second']['third']

C#, используя индексаторы и динамику C# 4.0,

class Tree
{
    private IDictionary<string, object> _dict = new Dictionary<string, object>();

    public dynamic this[string key]
    {
        get { return _dict.ContainsKey(key) ? _dict[key] : _dict[key] = new Tree(); }
        set { _dict[key] = value; }
    }
}

// Test:
var t = new Tree();
t["first"]["second"]["third"] = "text";
Console.WriteLine(t["first"]["second"]["third"]);

DynamicObject также можно использовать для реализации различных синтаксисов.

using System;
using System.Collections.Generic;
using System.Dynamic;

class Tree : DynamicObject
{
    private IDictionary<object, object> dict = new Dictionary<object, object>();

    // for t.first.second.third syntax
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var key = binder.Name;

        if (dict.ContainsKey(key))
            result = dict[key];
        else
            dict[key] = result = new Tree();

        return true;
    }
    
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dict[binder.Name] = value;
        return true;
    }

    // for t["first"]["second"]["third"] syntax
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
    {
        var key = indexes[0];

        if (dict.ContainsKey(key))
            result = dict[key];
        else
            dict[key] = result = new Tree();

        return true;
    }

    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
    {
        dict[indexes[0]] = value;
        return true;
    }
}

// Test:
dynamic t = new Tree();
t.first.second.third = "text";
Console.WriteLine(t.first.second.third);

// or,
dynamic t = new Tree();
t["first"]["second"]["third"] = "text";
Console.WriteLine(t["first"]["second"]["third"]);

См. также

[ редактировать ]

Примечания

[ редактировать ]
  1. ^ Например, Python выдает ошибку TypeError, если вызывается None.__getitem__. Разыменование нулевого указателя в C приводит к неопределенному поведению; многие реализации C предпочитают выдавать ошибку сегментации .
  1. ^ Шварц, Рэндал Л.; Феникс, Том (2003). Изучение объектов Perl . О'Рейли Медиа, Инк. с. 42 . ISBN  9780596004781 . Этот процесс называется аутовивификацией. Любая несуществующая переменная или переменная, содержащая undef, которая разыменовывается при поиске местоположения переменной (технически называемая контекстом lvalue), автоматически заполняется соответствующей ссылкой на пустой элемент...
  2. ^ «Стандарт HTML. Именованный доступ к объекту Window» .
  3. ^ «perl561delta — что нового в Perl v5.6.1» . Документация по программированию на Perl .
  4. ^ «Инициализация значения», справочник C++ (вики)
  5. ^ «Типы сопоставления — dict» . Проверено 13 июня 2016 г.
  6. ^ «Как лучше всего реализовать вложенные словари в Python?» . Проверено 13 июня 2016 г.
  7. ^ «Однострочное дерево в Python» . Проверено 27 декабря 2017 г.
  8. ^ «Карта (платформа Java SE 8)» . Проверено 17 мая 2015 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 842163c02a9872d07cce33b492be4073__1698910680
URL1:https://arc.ask3.ru/arc/aa/84/73/842163c02a9872d07cce33b492be4073.html
Заголовок, (Title) документа по адресу, URL1:
Autovivification - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)