Вложенные функции: Функция ЕСЛИ — вложенные формулы и типовые ошибки

Содержание

Go | Вложенные структуры

Вложенные структуры

Последнее обновление: 24.12.2017

Поля одних структур могут представлять другие структуры. Например:


package main
import "fmt"

type contact struct{
	email string
	phone string
}

type person struct{
	name string
	age int
	contactInfo contact
}

func main() {
	
	var tom = person {
		name: "Tom", 
		age: 24,
		contactInfo: contact{
			email: "[email protected]",
			phone: "+1234567899",
		},
	}
	tom.contactInfo.email = "[email protected]"
	
	fmt.Println(tom.contactInfo.email)		// [email protected]
	fmt.Println(tom.contactInfo.phone)		// +1234567899
}

В данном случае структура person имеет поле contactInfo, которое представляет другую структуру contact.

Можно сократить определение поля следующим образом:


package main
import "fmt"

type contact struct{
	email string
	phone string
}

type person struct{
	name string
	age int
	contact
}

func main() {
	
	var tom = person {
		name: "Tom", 
		age: 24,
		contact: contact{
			email: "tom@gmail.
com", phone: "+1234567899", }, } tom.email = "[email protected]" fmt.Println(tom.email) // [email protected] fmt.Println(tom.phone) // +1234567899 }

Поле contact в структуре person фактические эквивалентно свойству contact contact, то есть свойство называется contact и представляет тип contact. Это позволяет нам сократить путь к полям вложенной структуры. Например, мы можем написать tom.email, а не tom.contact.email. Хотя можно использовать и второй вариант.

Хранения ссылки на структуру того же типа

При этом надо учитывать, что структура не может иметь поле, которое представляет тип этой же структуры. Например:


type node struct{
	value int
	next node
}

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


package main
import "fmt"

type node struct{
	value int
	next *node
}

// рекурсивный вывод списка
func printNodeValue(n *node){
	
	fmt. Println(n.value)
	if n.next != nil{
		printNodeValue(n.next)
	}
}
func main() {
	
	first := node{value: 4}
	second := node{value: 5}
	third := node{value: 6}
	
	first.next = &second
	second.next = &third
	
	var current *node = &first
	for current != nil{
		fmt.Println(current.value)
		current = current.next
	}
}

Здесь определена структура node, которая представляет типичный узел односвязного списка. Она хранит значение в поле value и ссылку на следующий узел через указатель next.

В функции main создаются три связанных структуры, и с помощью цикла for и вспомогательного указателя current выводятся их значения.

замыкания, лексическое окружение, вложенные функции

На этом занятии подробно разберем области видимости данных в JavaScript и такое важное понятие как замыкание.

Для начала представим, что у нас имеется вот такая программа:

let name = "Иван";
getName("Привет!");
 
function getName(say) {
    console. log(name + ": " + say);
}

Как это работает в деталях. Как мы уже говорили, все функции, объявленные как Function Declaration, создаются JavaScript-движком в первую очередь. Но что значит создаются? В действительности, при запуске любого скрипта создается специальный объект (на уровне JavaScript-машины и недоступный программисту), называемый глобальным лексическим окружением (Lexical Envirnoment). Он состоит из двух частей:

  1. Environment Record – объект, в котором хранятся локальные данные как свойства этого объекта;
  2. Ссылка на внешнее лексическое окружение (если его нет, то эта ссылка равна null).

Так вот, объявление функции getName – это не что иное, как создание свойства getName в глобальном лексическом окружении:

Далее, начинает выполняться скрипт. Создается переменная name. Значит, в лексическом окружении появляется еще одно свойство – name:

Затем идет вызов функции getName(«Привет!»). В лексическом окружении ищется свойство getName со ссылкой на функцию. Так как оно там уже есть, то функция успешно вызывается. Но, каждый вызов функции создает свое лексическое окружение и картина будет выглядеть так:

Здесь аргументы функции становятся свойствами лексического окружения функции. Далее, выполняется строчка

console.log(name + ": " + say);

Переменная name сначала ищется в лексическом окружении функции. Не находит ее, тогда процесс поиска повторяется на следующем уровне, на который ссылается outer. В глобальном окружении переменная name существует, берется ее значение для вывода в консоль. То же самое происходит и с переменной say. Но она имеется в лексическом окружении самой функции, поэтому поиск здесь и завершается, не переходя к глобальному пространству. В результате мы видим сообщение «Иван: Привет!».

Как только функция завершила свою работу, ее лексическое окружение автоматически уничтожается с помощью встроенного в JavaScript механизма, называемый «

сборщик мусора».

Из этого примера следуют такие важные моменты:

  1. Внешнее лексическое окружение не имеет доступа к данным внутренних окружений.
  2. Поиск переменных начинается с текущего окружения и при необходимости последовательно переходит к внешним окружениям. Останавливается, как только переменная найдена.
  3. Лексическое окружение автоматически уничтожается, когда в нем более нет необходимости (на него нет внешних ссылок).

Здесь нужно лишь добавить: если переменная не находится, то при включенном режиме «use strict» она принимает значение undefined. Иначе, будет ссылаться на глобальный объект (в браузере – это window).

Исходя из всего сказанного, легко понять, что выведет в консоль следующий скрипт:

let name = "Иван";
getName("Привет!");
 
function getName(say) {
    let name = "Федор";
    console.log(name + ": " + say);
}

Да, мы видим строчку: «Федор: Привет!». То есть, переменная name была найдена в локальном окружении и взято значение «Федор», а не «Иван».

А вот, если мы выведем что-то в глобальном лексическом окружении:

console.log(name);
console.log(say);

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

if(…) {
// внутреннее лексическое окружение

}

операторы циклов:

while, for, do while(…) {
// внутреннее лексическое окружение
}

И в современных браузерах даже просто проставленные фигурные скобки:

{
// внутреннее лексическое окружение     
}

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

(function() {
    // код внутри изолирован от внешнего скрипта
    let name = "Григорий";
    console.log(name);
})();

Причем, он исполнялся в момент, когда интерпретатор JavaScript-машины доходил до этого места программы. Но теперь, в этом приеме нет необходимости и можно просто использовать фигурные скобки.

Еще раз обращу ваше внимание, что внутреннее лексическое окружение создается каждый раз при вызове функции. Если она вызывается несколько раз, то столько же и будет создано лексических окружений. Все лексические окружения автоматически удаляются при отсутствии внешних ссылок на них. Это важный момент!

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

function getName(say) {
    function getSay() {
         return ": " + say;
    }
 
    console. log(name + getSay());
}

Здесь функция getSay создана для удобства – вывода сообщения по определенному шаблону. Ее лексическое окружение будет вложено в лексическое окружение функции getName и, конечно же, она будет иметь доступ ко всем внутренним переменным функции getName.

Теперь, когда мы со всем этим разобрались, посмотрим на работу вот такой программы:

function createCounter() {
    let count = 0;
 
    return function() {
         return count++;
    };
}
 
let counter = createCounter();
console.log( counter() );

Вначале здесь объявляется функция createCounter, то есть, в глобальном окружении появляется такое свойство. Далее, эта функция вызывается. Создается ее локальное лексическое окружение с переменной count и анонимной функцией:

На эту анонимную функцию ссылается переменная counter из глобального окружения. В результате, после завершения выполнения функции createCounter() ее локальное окружение не уничтожается, так как все еще остается ссылка counter.

Далее, в программе идет вызов анонимной функции. Появляется еще одно лексическое пространство этой функции и картина выглядит уже вот так:

Анонимная функция берет переменную count из внешнего лексического пространства, возвращает ее и увеличивает на 1. Вот такое обращение в теле функции к переменной из внешнего лексического окружения в программировании называют замыканием.

При завершении, лексическое пространство анонимной функции уничтожается и остается два пространства:

Но значение count теперь равно 1. Если мы вызовем counter() еще раз, то получим значение 1 и переменная count станет равной 2. И так далее. Вот так работают замыкания в JavaScript. Причем, обратите внимание, если мы создадим еще один счетчик:

let counter2 = createCounter();

то будет создано еще одно лексическое пространство и оба счетчика будут работать независимо друг от друга:

console. log( counter2() );

Я постарался предельно просто изложить материал о лексических окружениях и замыканиях, опуская некоторые несущественные на мой взгляд детали. Если вы хотите научиться грамотно писать код на JavaScript, то этот материал следует хорошо знать. Особенно, часто на собеседованиях соискателя любят спрашивать о замыканиях и особенностях работы лексических окружений. И теперь, вы все это знаете.

Вложенные функции ЕСЛИ в Excel

Функция IF (ЕСЛИ) может быть вложенной в случае, когда нужно проверить несколько условий одновременно. Значение FALSE (ЛОЖЬ) может измениться на другое, если функция продолжит проверку. Для примера посмотрите на формулу ниже:

=IF(A1=1,"Bad",IF(A1=2,"Good",IF(A1=3,"Exellent","No Valid Score")))
=ЕСЛИ(A1=1;"Bad";ЕСЛИ(A1=2;"Good";ЕСЛИ(A1=3;"Exellent";"No Valid Score")))

  1. Если значение в ячейке A1 равно 1, функция возвращает Bad.
  2. Если значение в ячейке A1 равно 2, функция возвращает Good.
  3. Если значение в ячейке A1 равно 3, функция возвращает Excellent.
  4. Если ячейка A1 принимает другое значение, функция возвращает No Valid Score.

Вот еще один пример:

=IF(A1<=10,350,IF(A1<=20,700,IF(A1<=30,1400,2000)))
=ЕСЛИ(A1<=10;350;ЕСЛИ(A1<=20;700;ЕСЛИ(A1<=30;1400;2000)))

  1. Если значение в ячейке A1 меньше или равно 10, функция возвращает 350.
  2. Если значение в ячейке A1 больше, чем 10, но меньше или равно 20, функция возвращает 700.
  3. Если значение в ячейке A1 больше, чем 20, но меньше или равно 30, функция возвращает 1400.
  4. Если значение в ячейке A1 больше, чем 30, функция возвращает 2000.

Примечание: Возможно, в своей формуле вы захотите использовать “<” вместо “<=“, чтобы немного изменить границы.

Оцените качество статьи. Нам важно ваше мнение:

Вложение Функций | ora-sql.ru

  • Однострочные функции могут быть вложены сколь угодно.

  • Вложенные функции оцениваются от самого глубокого уровня к наименее глубокому уровню.

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

Вложение функций: Пример 1

Пример на рисунке выводит на экран фамилии сотрудников в отделе 60. Оценка SQL-оператора включает три шага:

  1. Внутренняя функция получает первые восемь символов фамилии.

    Result1 = SUBSTR (LAST_NAME, 1, 8)

  2. Внешняя функция сцепляет результат с _US.

    Result2 = CONCAT(Result1, '_US')

  3. Самая внешняя функция преобразовывает результаты в верхний регистр.

Все выражение становится заголовком столбца, потому что никакой псевдоним столбца не был задан.

Пример:

Выведите на экран дату следующей пятницы, которая отстоит на шесть месяцев с даты приема на работу. Получающаяся дата должна быть выведена в формате Friday, August 13th, 1999. Упорядочить результаты по дате приема на работу.

    SELECT TO_CHAR(NEXT_DAY(ADD_MONTHS
    (hire_date, 6), 'FRIDAY'),
    'fmDay, Month ddth, YYYY')
    "Next 6 Month Review"
FROM employees
ORDER BY hire_date;

Вложенные функции: Пример 2

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

Во-первых, внутренняя функция ROUND выполняется, чтобы округлить значение зарплаты, разделенной на 7, до двух десятичных разрядов. Функция TO_CHAR затем используется, чтобы отформатировать результат функции ROUND.

Отметьте: D и G, определенные в параметре функции TO_CHAR, являются элементами числового формата. D возвращает десятичный символ в указанной позиции. G используется в качестве разделителя группы.

Далее: Результаты Ограничения Групп

Функция в функции в Excel

Пример 1: Два условия

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



Второе условие — числа, которые будут суммироваться. Их тоже определяем заранее, чтобы было проще создавать функцию.

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

  1. Создадим функцию через отдельное окно, нажав по кнопке с тематическим значком.
  2. Пример базируется на корневой функции «ЕСЛИ», поэтому в окне «Вставка функции» выберите именно ее.
  3. В качестве логического выражения записывайте функцию, считающую среднее значение и определяющую, больше ли оно указанного числа. Тогда строка обретет вид СРЗНАЧ(A1:A6)>300, где A1 и A6 — диапазон захватываемых ячеек, > — знак «больше», а 300 — целевое среднее значение, являющееся истинным.
  4. Другая функция, используемая внутри корневой, называется «СУММ» — она и будет выводить сумму чисел при истинном значении, поэтому записывается во втором поле в представлении СУММ(C1:D1:E1:F1).
  5. Если среднее значение не соответствует требованию, выведем любое оповещающее сообщение, например «недостача». Проверьте правильность написания функций и сохраните результат.
  6. Сейчас функция ЕСЛИ находится в состоянии «истина», а значит, в заданной клетке отобразится сумма указанного диапазона.
  7. Если же условия ложные, всплывет указанное сообщение или 0.
  8. Исходя из увиденного примера, становится понятно, что внутри той же функции ЕСЛИ можно вписать и любую другую функцию, что и выполняет условие рассматриваемой темы. Попробуйте провести эксперименты и заменить рассмотренную функцию на другую, вписав внутри необходимые данные, не забывая и про синтаксис программы.

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

Подробнее: Мастер функций в программе Microsoft Excel

Пример 2: Три и более условий

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

  1. Создадим отдельную формулу при использовании все той же корневой функции ЕСЛИ.

  2. Начните создавать формулу, нажав по нужной пустой ячейке и написав =ЕСЛИ(B2=C2;»Не изменилась»). Как можно понять, после открывающихся скобок идет первое условие, а при его истине выводится сообщение «Не изменилась».
  3. Поставьте знак ; и сразу же впишите новую функцию ЕСЛИ без знака =, где внутри содержится второе условие.
  4. Точно так же поступите с третьим условием и расставьте все закрывающиеся скобки.
  5. При сохранении результата вы увидите, что сообщение показывается верно, а также сможете скопировать саму формулу для других ячеек, поменяв только сравнение целевых цен.

Для лучшего понимания оставим полную строку формулы с функцией в функции в правильном ее виде =ЕСЛИ(B2=C2;»Не изменилась»;ЕСЛИ(B2C2;»Уменьшилась»))). Если требуется, скопируйте ее и используйте в своих целях, изменив условия и значения.

Мы рады, что смогли помочь Вам в решении проблемы.
Опишите, что у вас не получилось. Наши специалисты постараются ответить максимально быстро.
Помогла ли вам эта статья?
ДА НЕТ

Функции в Python: замыкания

В этой статье мы рассмотрим замыкания (closures) в Python: как их определять и когда их стоит использовать.

Нелокальная переменная во вложенной функции

Прежде чем перейти к тому, что такое замыкание, мы должны сначала понять, что такое вложенная функция и нелокальная (nonlocal) переменная.

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

В Python нелокальные переменные по умолчанию доступны только для чтения. Если нам необходимо их модифицировать, то мы должны объявить их явно как нелокальные (используя ключевое слово nonlocal).

Ниже приведен пример вложенной функции, обращающейся к нелокальной переменной.

def print_msg(msg):
    # объемлющая функция

    def printer():
        # вложенная функция
        print(msg)

    printer()

# Output: Hello
print_msg("Hello")

Мы видим, что вложенная функция printer() смогла получить доступ к нелокальной переменной msg объемлющей функции print_msg(msg).

Определение замыкания

Что произойдет в приведенном выше примере, если последняя строка функции print_msg() вернет функцию printer() вместо ее вызова? Определим данную функцию следующим образом:

def print_msg(msg):
    # объемлющая функция

    def printer():
        # вложенная функция
        print(msg)

    return printer  # возвращаем вложенную функцию


# теперь попробуем вызвать эту функцию
# Output: Hello
another = print_msg("Hello")
another()

Это необычно.

Функция print_msg() вызывалась со строкой «Hello», а возвращаемая функция была присвоена переменной another. При вызове another() сообщение все еще сохранялось в памяти, хотя мы уже закончили выполнение функции print_msg().

Этот метод, с помощью которого некоторые данные (в данном случае строка «Hello») прикрепляются к некоторому коду, в Python называется замыканием.

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

Попробуйте выполнить следующее, чтобы увидеть результат:

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

Здесь возвращаемая функция все еще работает, даже если исходная функция была удалена.

Когда мы имеем дело с замыканием?

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

Критерии, которые должны быть выполнены для создания замыкания в Python, изложены в следующих пунктах:

  • У нас должна быть вложенная функция (функция внутри функции).
  • Вложенная функция должна ссылаться на значение, определенное в объемлющей функции.
  • Объемлющая функция должна возвращать вложенную функцию.

Когда стоит использовать замыкания?

Так для чего же нужны замыкания?

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

Если в классе необходимо реализовать небольшое количество методов (в большинстве случаев один метод), замыкания могут обеспечить альтернативное и более элегантное решение. Но когда количество атрибутов и методов становится больше, лучше реализовать класс.

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

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier


times3 = make_multiplier_of(3)

times5 = make_multiplier_of(5)

# Output: 27
print(times3(9))

# Output: 15
print(times5(3))

# Output: 30
print(times5(times3(2)))

Декораторы в Python также широко используют замыкания.

В заключение следует отметить, что можно найти значения, включенные в функцию замыкания.

Все объекты функций имеют атрибут __closure__, который возвращает кортеж объектов cell, если это функция замыкания. Ссылаясь на приведенный выше пример, мы знаем, что times3 и times5 являются замыканиями.

>>> make_multiplier_of. __closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)

Объект cell имеет атрибут cell_contents, который хранит значение.

>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5

Больше примеров замыканий вы можете найти по ссылке.

Использовать вложенные функции в формуле

Использование функции в качестве одного из аргументов в формуле, которая использует функцию, называется вложением, и мы будем называть эту функцию вложенной функцией. Например, вложив функции СРЕДНЕЕ и СУММ в аргументы функции ЕСЛИ, следующая формула суммирует набор чисел (G2: G5), только если среднее значение другого набора чисел (F2: F5) больше 50. В противном случае возвращается 0.

Функции СРЗНАЧ и СУММ вложены в функцию ЕСЛИ.

В формулу можно вложить до 64 уровней функций.

  1. Щелкните ячейку, в которую вы хотите ввести формулу.

  2. Чтобы начать формулу с функцией, щелкните Вставить функцию в строке формул .

    Excel вставит вам знак равенства ( = ).

  3. В поле Или выберите категорию , выберите Все .

    Если вы знакомы с категориями функций, вы также можете выбрать категорию.

    Если вы не уверены, какую функцию использовать, вы можете ввести вопрос, описывающий, что вы хотите сделать, в поле Поиск функции (например, «добавить числа» возвращает функцию СУММ ).

  4. Чтобы ввести другую функцию в качестве аргумента, введите нужную функцию в поле аргумента.

    Части формулы, отображаемые в диалоговом окне Аргументы функции , отражают функцию, выбранную на предыдущем шаге.

    Если вы щелкнули IF , диалоговое окно аргументы функции отобразит аргументы для функции IF .Чтобы вложить другую функцию, вы можете ввести ее в поле аргумента. Например, вы можете ввести СУММ (G2: G5) в поле Value_if_true функции IF .

  5. Введите любые дополнительные аргументы, необходимые для завершения формулы.

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

    Совет: Для получения дополнительных сведений о функции и ее аргументах щелкните Справка по этой функции .

  6. После того, как вы введете аргументы для формулы, нажмите ОК .

  1. Щелкните ячейку, в которую вы хотите ввести формулу.

  2. Чтобы начать формулу с функцией, щелкните Вставить функцию в строке формул .

  3. В диалоговом окне «Вставить функцию» в поле « Выбрать категорию» выберите Все .

    Если вы знакомы с категориями функций, вы также можете выбрать категорию.

  4. Чтобы ввести другую функцию в качестве аргумента, введите функцию в поле аргумента в построителе формул или непосредственно в ячейку.

  5. Введите любые дополнительные аргументы, необходимые для завершения формулы.

  6. После ввода аргументов формулы нажмите клавишу ВВОД.

Примеры

Ниже показан пример использования вложенных функций ЕСЛИ для присвоения буквенной оценки числовому результату теста.

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

Оценка

45

90

78

Формула

Описание

Результат

‘= ЕСЛИ (A2> 89, «A», ЕСЛИ (A2> 79, «B», ЕСЛИ (A2> 69, «C», ЕСЛИ (A2> 59, «D», «F»)))))

Использует вложенные условия ЕСЛИ для присвоения буквенной оценки баллу в ячейке A2.

= ЕСЛИ (A2> 89, «A», ЕСЛИ (A2> 79, «B», ЕСЛИ (A2> 69, «C», ЕСЛИ (A2> 59, «D», «F»))))

‘= ЕСЛИ (A3> 89, «A», IF (A3> 79, «B», IF (A3> 69, «C», IF (A3> 59, «D», «F»)))))

Использует вложенные условия ЕСЛИ для присвоения буквенной оценки баллу в ячейке A3.

= ЕСЛИ (A3> 89, «A», ЕСЛИ (A3> 79, «B», ЕСЛИ (A3> 69, «C», ЕСЛИ (A3> 59, «D», «F»))))

‘= ЕСЛИ (A4> 89, «A», IF (A4> 79, «B», IF (A4> 69, «C», IF (A4> 59, «D», «F»))))

Использует вложенные условия ЕСЛИ для присвоения буквенной оценки баллу в ячейке A4.

= ЕСЛИ (A4> 89, «A», IF (A4> 79, «B», IF (A4> 69, «C», IF (A4> 59, «D», «F»))))

Нужна дополнительная помощь?

Вы всегда можете спросить эксперта в техническом сообществе Excel, получить поддержку в сообществе Answers или предложить новую функцию или улучшение в Excel User Voice.

См. Также

Видео: вложенные функции ЕСЛИ

Добавление вложенных функций и вложенных рабочих процессов

  • 3 минуты на чтение

В этой статье

Применимо к: Windows Server 2012, Windows Server 2012 R2

В Windows PowerShell® Workflow вы можете включать функции и вложенные рабочие процессы для повторного использования и организации команд в рабочем процессе сценария.В этом разделе объясняются правила создания и вызова вложенных функций и рабочих процессов.

Добавление вложенных функций и вложенных рабочих процессов

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

  рабочий процесс Один
{
    "Один"
    Два
    рабочий процесс два
    {
        "Два"
        Три
        Функция третья
        {
            "Три"
            функция Five {"Five"}
            Рабочий процесс Четыре {"Четыре"; 5}
            Четыре
        }
    }
}
  

Использование параметров и переменных во вложенных функциях и рабочих процессах

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

Примечание

УСТРАНЕНИЕ НЕПОЛАДОК ПРИМЕЧАНИЕ. Значения переменных, созданных в области рабочих процессов, могут быть недоступны для вложенных функций. Значения параметров рабочего процесса и переменных, созданных в области рабочего процесса, могут быть недоступны для вложенных рабочих процессов.Рабочие процессы с трехуровневой вложенностью не поддерживают никаких общих параметров, включая общие параметры рабочего процесса.

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

Например, следующий пример рабочего процесса включает вложенный рабочий процесс Get-ModuleAlias.Чтобы гарантировать, что вложенный рабочий процесс имеет доступ к значению параметра ModuleName рабочего процесса, определите аналогичный параметр во вложенном рабочем процессе и передайте значение параметра ModuleName при вызове вложенного рабочего процесса.

  Get-ModuleProperties рабочего процесса
{
    Param
    (
         [параметр (обязательный = $ true)]
         [Строка]
         $ ModuleName
    )

    рабочий процесс Get-ModuleAlias
    {
      Param
      (
         [параметр (обязательный = $ true)]
         [Строка]
         $ ModuleNameForAlias,

       )
       ((Get-Module -Name $ ModuleNameForAlias ​​-ListAvailable). ExportedAliases) .Keys.
    }
    Get-ModuleAlias ​​-ModuleName $ ModuleNameForAlias
}
  

Вызов вложенных рабочих процессов и функций

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

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

      Рабочий процесс Тестовый рабочий процесс
    {
        param ($ ModuleName)
    
        функция Initialize-Files
        {...}
    
        рабочий процесс Get-Metadta
        {
            ...
            Инициализировать файлы
            Get-Configuration
            Get-DataSource
            Get-Module -ModuleName $ ModuleName
            функция Get-DataSource
            {
               ...
            }
        }
    
        функция Get-Configuration
        {
           . ..
        }
    }
      
  • Вложенные рабочие процессы могут вызывать рабочие процессы и функции в текущей области и любой родительской области, как показано в следующем примере.

      # In Test-Nested.ps1
    function Zero {"Zero"}
    рабочий процесс один
    {
    "Один"
    Два
    Три
    Четыре
    рабочий процесс четыре
        {
            «Четыре»; Два; Три; 5;
            рабочий процесс Five {"Five"; Два; Три; Нуль}
        }
    }
    функция Два {"Два"}
    рабочий процесс Три {"Три"}
    Один
      

    Результат выполнения сценария Test-Nested.ps1 выглядит следующим образом.

      PS C: \ Test-Nested.ps1
    Один
    Два
    Три
    Четыре
    Два
    Три
    5
    Два
    Три
    Нуль
      
  • Рекурсивный вызов, как показано в следующем примере, не разрешен в рабочих процессах.

      рабочий процесс один
    {
    "Один"
    Два
    }
    
    рабочий процесс два
    {
    "Два"
    Один
    }
      

    Рекурсивные вызовы разрешены в скриптах и ​​функциях.

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

      рабочий процесс Test-Workflow
    {
        рабочий процесс Test1 {"Test1"}
        function Test1 {"Привет, Test1"}
    }
    
    В строке: 4 символа: 5
    + функция Test1 {"Привет, Test1"}
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Функцию или рабочий процесс Test1 нельзя переопределить.+ CategoryInfo: ParserError: (:) [], ParseException
        + FullyQualifiedErrorId: FunctionRedefinitionNotAllowed
      
  • Если имя вложенного рабочего процесса или функции совпадает с именем рабочего процесса или функции в родительской области, вызовы этого имени вызовут рабочий процесс или функцию в текущей (рабочий процесс) области.

    В следующем примере вызов «Test-Nested» вызывает рабочий процесс Test-Nested. Если бы рабочий процесс Test-Nested имел другое имя, вызов «Test-Nested» вызвал бы функцию Test-Nested.

      function Test-Nested {"Test-Nested Function"}
    рабочий процесс Test-Workflow
    {
        Вложенный тестовый процесс {"Вложенный тестовый рабочий процесс"}
        Вложенный тест
    }
    PS C: \> Тестовый рабочий процесс
    Вложенный рабочий процесс
      

    В стандартном скрипте или функции Windows PowerShell имена вложенных функций можно использовать повторно. Вызов вызывает последнюю функцию, определенную с конкретным именем перед вызовом.

Функция ЕСЛИ — вложенные формулы и предотвращение ловушек

Функция ЕСЛИ позволяет вам логически сравнивать значение и ожидаемое значение, проверяя условие и возвращая результат, если оно истинно или ложно.

Таким образом, оператор IF может иметь два результата. Первый результат — если ваше сравнение — Истина, второй — если ваше сравнение — Ложь.

Операторы

IF невероятно надежны и составляют основу многих моделей электронных таблиц, но они также являются основной причиной многих проблем с электронными таблицами. В идеале оператор IF должен применяться к минимальным условиям, таким как «Мужской / Женский», «Да / Нет / Может быть», и это лишь некоторые из них, но иногда вам может потребоваться оценить более сложные сценарии, требующие вложенности * более 3-х функций ЕСЛИ вместе.

* «Вложение» означает объединение нескольких функций в одну формулу.

Используйте функцию ЕСЛИ, одну из логических функций, чтобы вернуть одно значение, если условие истинно, и другое значение, если оно ложно.

Синтаксис

IF (логический_тест, значение_если_ истинно, [значение_если_ ложь])

Например:

Имя аргумента

Описание

логический_тест

(обязательно)

Состояние, которое вы хотите проверить.

значение_if_true

(обязательно)

Значение, которое вы хотите вернуть, если результатом logic_test является ИСТИНА.

значение_if_false

(опционально)

Значение, которое вы хотите вернуть, если результатом logic_test является ЛОЖЬ.

Замечания

Хотя Excel позволяет вкладывать до 64 различных функций ЕСЛИ, делать это совсем не рекомендуется. Почему?

  • Множественные операторы IF требуют серьезного размышления, чтобы правильно построить и убедиться, что их логика может правильно рассчитывать каждое условие до самого конца. Если вы не разместите формулу на 100% точно, она может сработать в 75% случаев, но в 25% случаев будет давать неожиданные результаты.К сожалению, шансы, что вы поймаете эти 25%, невелики.

  • Множественные операторы ЕСЛИ могут стать невероятно трудными для обслуживания, особенно когда вы возвращаетесь через некоторое время и пытаетесь выяснить, что вы или, что еще хуже, кто-то другой, пытался сделать.

Если вы столкнулись с оператором IF, который, кажется, продолжает расти, и конца ему не видно, пора отложить мышь и пересмотреть свою стратегию.

Давайте посмотрим, как правильно создать сложный вложенный оператор IF, используя несколько IF, и когда понять, что пора использовать другой инструмент в вашем арсенале Excel.

Примеры

Ниже приведен пример относительно стандартного вложенного оператора ЕСЛИ для преобразования результатов тестов учащихся в их буквенный эквивалент.

  • = ЕСЛИ (D2> 89, «A», ЕСЛИ (D2> 79, «B», ЕСЛИ (D2> 69, «C», IF (D2> 59, «D», «F»))))

    Этот сложный вложенный оператор IF следует простой логике:

  1. Если результат теста (в ячейке D2) больше 89, то ученик получает

    A
  2. org/ListItem»>

    Если результат теста больше 79, ученик получает

    B
  3. Если результат теста больше 69, ученик получает

    C
  4. Если результат теста больше 59, то студент получает D

    .
  5. В противном случае студент получает F

Этот конкретный пример относительно безопасен, поскольку маловероятно, что корреляция между результатами теста и буквенными оценками изменится, поэтому он не потребует значительного обслуживания. Но вот мысль — а что, если вам нужно разделить оценки между A +, A и A- (и так далее)? Теперь ваш оператор IF с четырьмя условиями необходимо переписать, чтобы он содержал 12 условий! Вот как теперь будет выглядеть ваша формула:

  • = ЕСЛИ (B2> 97, «A +», ЕСЛИ (B2> 93, «A», ЕСЛИ (B2> 89, «A -», ЕСЛИ (B2> 87, «B +», ЕСЛИ (B2> 83, « B », ЕСЛИ (B2> 79,« B- », ЕСЛИ (B2> 77,« C + », ЕСЛИ (B2> 73,« C », ЕСЛИ (B2> 69,« C — », ЕСЛИ (B2> 57 , «D +», ЕСЛИ (B2> 53, «D», ЕСЛИ (B2> 49, «D -», «F»))))))))))))

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

Совет: Для каждой функции в Excel требуется открывающая и закрывающая круглые скобки (). Excel попытается помочь вам выяснить, что куда идет, раскрашивая разные части формулы, когда вы ее редактируете.Например, если вы редактируете приведенную выше формулу, при перемещении курсора за каждую из конечных скобок «)» соответствующая открывающая скобка станет того же цвета. Это может быть особенно полезно в сложных вложенных формулах, когда вы пытаетесь выяснить, достаточно ли у вас совпадающих круглых скобок.

Дополнительные примеры

Ниже приведен очень распространенный пример расчета комиссии с продаж на основе достигнутых уровней дохода.

  • = ЕСЛИ (C9> 15000,20%, ЕСЛИ (C9> 12500,17.5%, ЕСЛИ (C9> 10000,15%, IF (C9> 7500,12,5%, IF (C9> 5000,10%, 0)))))

В этой формуле говорится: ЕСЛИ (C9 больше 15000, тогда возвращается 20%, ЕСЛИ (C9 больше 12,500, затем возвращается 17,5%, и так далее …

)

Несмотря на то, что она очень похожа на предыдущий пример оценок, эта формула является отличным примером того, насколько сложно поддерживать большие операторы ЕСЛИ — что вам нужно сделать, если ваша организация решит добавить новые уровни компенсации и, возможно, даже изменить существующие долларовые или процентные значения? У вас будет много работы!

Совет: Чтобы облегчить чтение длинных формул, в строку формул можно вставить разрывы строк. Просто нажмите ALT + ENTER перед текстом, который вы хотите перенести на новую строку.

Вот пример сценария комиссии с неработающей логикой:

Вы видите, что не так? Сравните порядок сравнения доходов с предыдущим примером. Куда он идет? Верно, он идет снизу вверх (от 5000 до 15000 долларов), а не наоборот. Но почему это должно быть так важно? Это большое дело, потому что формула не может пройти первую оценку для любого значения выше 5000 долларов.Допустим, у вас есть доход 12 500 долларов — оператор IF вернет 10%, потому что он превышает 5000 долларов, и на этом остановится. Это может быть невероятно проблематичным, потому что во многих ситуациях ошибки такого типа остаются незамеченными до тех пор, пока не окажут негативного воздействия. Итак, что вы можете сделать, зная, что есть серьезные подводные камни со сложными вложенными операторами IF? В большинстве случаев вы можете использовать функцию ВПР вместо построения сложной формулы с функцией ЕСЛИ. Используя VLOOKUP, вам сначала нужно создать справочную таблицу:

  • = ВПР (C2; C5: D17,2; ИСТИНА)

Эта формула требует искать значение в C2 в диапазоне C5: C17.Если значение найдено, вернуть соответствующее значение из той же строки в столбце D.

  • = ВПР (B9; B2: C6,2; ИСТИНА)

Точно так же эта формула ищет значение в ячейке B9 в диапазоне B2: B22. Если значение найдено, вернуть соответствующее значение из той же строки в столбце C.

Примечание. Обе эти ВПР используют аргумент ИСТИНА в конце формул, что означает, что мы хотим, чтобы они искали приблизительное совпадение.Другими словами, он будет соответствовать точным значениям в таблице поиска, а также любым значениям, которые попадают между ними. В этом случае таблицы поиска необходимо отсортировать в порядке возрастания от наименьшего к наибольшему.

ВПР рассматривается здесь более подробно, но это, безусловно, намного проще, чем 12-уровневый сложный вложенный оператор IF! Есть и другие, менее очевидные преимущества:

  • Справочные таблицы

    VLOOKUP открыты и легко видны.

  • Значения таблицы можно легко обновить, и вам никогда не придется прикасаться к формуле, если ваши условия изменятся.

  • Если вы не хотите, чтобы люди видели вашу справочную таблицу или мешали ей, просто поместите ее на другой лист.

Знаете ли вы?

Теперь есть функция IFS, которая может заменить несколько вложенных операторов IF одной функцией.Итак, вместо нашего примера начальных оценок, в котором есть 4 вложенных функции ЕСЛИ:

  • = ЕСЛИ (D2> 89, «A», ЕСЛИ (D2> 79, «B», ЕСЛИ (D2> 69, «C», IF (D2> 59, «D», «F»))))

Его можно сделать намного проще с помощью одной функции IFS:

  • = IFS (D2> 89, «A», D2> 79, «B», D2> 69, «C», D2> 59, «D», TRUE, «F»)

Функция IFS великолепна, потому что вам не нужно беспокоиться обо всех этих операторах IF и скобках.

Нужна дополнительная помощь?

Вы всегда можете спросить эксперта в техническом сообществе Excel, получить поддержку в сообществе Answers или предложить новую функцию или улучшение в Excel User Voice.

Связанные темы

Видео: Расширенные функции ЕСЛИ
Функция IFS (Microsoft 365, Excel 2016 и более поздние версии)
Функция СЧЁТЕСЛИ подсчитывает значения на основе одного критерия.
Функция СЧЁТЕСЛИМН будет подсчитывать значения на основе нескольких критериев.
Функция СУММЕСЛИ суммирует значения на основе одного критерия.
Функция СУММЕСЛИМН суммирует значения на основе нескольких критериев.
И функция
функция ИЛИ
функция ВПР
Обзор формул в Excel
Как избежать неправильных формул
Обнаружение ошибок в формулах
Логические функции
Функции Excel (по алфавиту)
Функции Excel (по категориям)

Вложенная функция

Определения вложенных функций можно сравнить с тем, как матрешка встраивается в более крупные версии самой себя на нескольких уровнях.

В компьютерном программировании вложенная функция (или вложенная процедура / подпрограмма ) — это функция, которая лексически (текстуально) инкапсулирована внутри другой функции. Он может вызываться только включающей функцией или функциями, прямо или косвенно вложенными в одну и ту же включающую функцию. Другими словами, объем вложенной функции ограничен включающей функцией. Вложенность теоретически возможна на любом уровне глубины, хотя на практике обычно используются только несколько уровней.

Пример

Пример использования синтаксиса Паскаля:

функция E (x: real): real;
 
    функция F (y: действительный): действительный;
    начать
        F: = х + у
    конец;
 
начать
    E: = F (3)
конец;
 

и тот же пример в синтаксисе GNU C:

float E (float x)
{
    float F (float y)
    {
        вернуть x + y;
    }
    вернуть F (3);
}
 

Функция F вложена в E (обратите внимание, что x отображается в F , а y невидимо за пределами F ).

Назначение

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

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

языков

Хорошо известные языки, поддерживающие лексически вложенные функции, включают:

  • Языки на основе АЛГОЛа, такие как АЛГОЛ 68, Simula, Паскаль, Модула-2, Модула-3, Оберон и Ада.
  • Современные версии Lisp (с лексической областью видимости), такие как Scheme и Common Lisp.
  • Сценарий ECMA (JavaScript и ActionScript).
  • Полная поддержка в Scala
  • Различные степени поддержки языков сценариев, таких как Ruby, Python и Perl (начиная с версии 6).
  • Существует также язык, связанный с C, с вложенными функциями, язык D.
  • GCC также поддерживает вложенные функции в C в качестве расширения языка. [1]
  • Fortran, начиная с Fortran-90, поддерживает один уровень вложенных ( СОДЕРЖИТ ) подпрограмм и функций.

Функциональные языки

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

Некоторые языки без прямой поддержки

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

  • C ++ позволяет определять классы внутри классов, обеспечивая возможность использования методов класса аналогично вложенным функциям на уровне one (см. Объект функции в C ++).
  • Visual Basic и C #, используя анонимные методы или лямбда-выражения.
  • Java с помощью обходного пути, который состоит в анонимном классе, содержащем единственный метод.Также может использоваться именованный класс, объявленный локальным для метода.

Реализация

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

Любой нелокальный объект X достигается через ссылки доступа в кадрах активации в машинном стеке. Вызывающий, C, помогает вызываемой процедуре P, проталкивая прямую ссылку на последнюю активацию непосредственной лексической инкапсуляции P (P) до самого вызова.Затем P может быстро найти правильную активацию для определенного X, следуя фиксированному числу (P.depth — X.depth) ссылок (обычно небольшое количество).
Вызывающий создает эту прямую ссылку (сам), следуя старым ссылкам C.depth — P.depth + 1, что приводит к последней активации (P), а затем временно соединяет их с прямой ссылкой на та активация; позднее ссылка исчезает вместе с буквой P, в результате чего старые ссылки под ней могут снова использоваться.
Обратите внимание, что P виден для C и, следовательно, может вызываться им, если (P) = C / (C) / ((C)) / и т. Д.

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

Другой способ реализации вложенных функций, который используется некоторыми компиляторами, — это преобразование («подъем») вложенных функций в не вложенные функции (где дополнительные параметры заменяют ссылки доступа) с использованием процесса, известного как лямбда-подъем, на промежуточном этапе в компиляция. «Вложенные функции — Использование коллекции компиляторов GNU (GCC)». Проект GNU. http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html. Проверено 6 января 2007.

Внешние ссылки

вложенных функций в Swift (с примерами)

Если функция существует внутри тела другой функции, она называется вложенной функцией.

Синтаксис вложенной функции

func funcname () {
    // операторы внешней функции
    func anotherFuncname () {
        // операторы внутренней функции
    }
}
 

Здесь функция anotherFuncname находится внутри тела другой функции funcname .

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


Пример 1: Вложенная функция без возвращаемых значений

  func outputMessageByGreeting (_ message: String) {
    
    func addGreetingAndPrint () {
        print ("Привет! \ (сообщение)")
    }
    addGreetingAndPrint ()
}
outputMessageByGreeting ("Джек")
  

Когда вы запустите программу, вывод будет:

  Здравствуйте! Джек  

В приведенной выше программе вложенная функция addGreetingAndPrint () вызывается из включающей функции outputMessageByGreeting () .

Оператор outputMessageByGreeting ("Jack") вызывает внешнюю функцию. И оператор addGreetingAndPrint () внутри внешней функции вызывает метод, который выводит Hello! Джек в консоли.

Невозможно вызвать функцию addGreetingAndPrint вне функции outputMessageByGreeting .


Пример 2: Вложенная функция с параметрами и возвращаемыми значениями

Вложенные функции могут содержать функции с параметрами и возвращаемыми значениями.

  func operation (с символом: String) -> (Int, Int) -> Int {
    
    func add (num1: Int, num2: Int) -> Int {
        вернуть num1 + num2
    }
    
    func subtract (num1: Int, num2: Int) -> Int {
        вернуть num1 - num2
    }
    пусть операция = (символ == "+")? добавить: вычесть
    возвратная операция
}

пусть операция = работа (с: "+")
пусть результат = операция (2, 3)
печать (результат)
  

Когда вы запустите программу, вывод будет:

  5  

В вышеуказанной программе

  • внешняя функция — Operating () , с возвращаемым значением типа Function (Int, Int) -> Int .
  • , а внутренние (вложенные) функции — add () и subtract () .

Вложенные функции add (), и subtract () в некотором роде используются вне функции включения Operating () . Это возможно, потому что внешняя функция возвращает одну из этих функций.

Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *