0Pricing
C# Academy · Урок

Статические локальные функции

Предотвращайте захват переменных ради ясности и производительности.

«Статические локальные функции» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Статические локальные функции

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

Объявление статической локальной функции

Добавьте модификатор static перед возвращаемым типом. Функция по-прежнему может принимать параметры и возвращать значения, но не может обращаться к внешним локальным переменным.

using System;

public class Program
{
    public static void Main()
    {
        static int Square(int n) => n * n; // captures nothing

        Console.WriteLine(Square(6));
    }
}

Захват запрещён

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

using System;

public class Program
{
    public static void Main()
    {
        int factor = 3;
        // factor must be passed in, not captured
        static int Scale(int n, int f) => n * f;

        Console.WriteLine(Scale(5, factor));
    }
}

Избежание скрытых выделений памяти

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

using System;

public class Program
{
    public static void Main()
    {
        // Pure helper, no closure object created
        static bool IsEven(int n) => n % 2 == 0;

        for (int i = 0; i < 5; i++)
            Console.WriteLine(i + ": " + IsEven(i));
    }
}

Самодокументируемое намерение

Ключевое слово static сообщает читателям, что вспомогательная функция зависит только от своих аргументов. Эта гарантия упрощает анализ и тестирование функции.

using System;

public class Program
{
    public static void Main()
    {
        static int Clamp(int value, int lo, int hi)
            => value < lo ? lo : value > hi ? hi : value;

        Console.WriteLine(Clamp(15, 0, 10));
        Console.WriteLine(Clamp(-3, 0, 10));
    }
}

Компилятор запрещает захват

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

using System;

public class Program
{
    public static void Main()
    {
        int seed = 7;
        // Correct: seed is passed explicitly, not captured
        static int Mix(int x, int s) => x * 31 + s;

        Console.WriteLine(Mix(2, seed));
    }
}

Статические локальные функции с рекурсией

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

using System;

public class Program
{
    public static void Main()
    {
        static int Power(int baseN, int exp)
            => exp == 0 ? 1 : baseN * Power(baseN, exp - 1);

        Console.WriteLine(Power(2, 10));
    }
}

Сочетание с параметрами out

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

using System;

public class Program
{
    public static void Main()
    {
        static bool TryParsePositive(string s, out int value)
        {
            value = 0;
            return int.TryParse(s, out value) && value > 0;
        }

        if (TryParsePositive("42", out int n))
            Console.WriteLine("got " + n);
        Console.WriteLine(TryParsePositive("-1", out _));
    }
}

Передача статических локальных функций как делегатов

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

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        static bool IsBig(int n) => n > 100;

        var nums = new List<int> { 50, 150, 200, 10 };
        Console.WriteLine(nums.Count(IsBig));
    }
}

Когда предпочитать static

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

using System;

public class Program
{
    public static void Main()
    {
        static string Describe(int score)
        {
            if (score >= 90) return "A";
            if (score >= 80) return "B";
            return "C";
        }

        Console.WriteLine(Describe(95));
        Console.WriteLine(Describe(82));
    }
}

Попробуйте сами

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

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        static bool IsLeapYear(int year)
            => (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;

        var years = new List<int> { 1900, 2000, 2004, 2021, 2024 };
        Console.WriteLine(string.Join(", ", years.Where(IsLeapYear)));
    }
}

Быстрая проверка

Вспомните, что добавляет static локальной функции.

Повторение

Статическая локальная функция static ничего не захватывает.

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

Часто задаваемые вопросы

Урок «Статические локальные функции» бесплатный?

Да — полный текст урока «Статические локальные функции» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Статические локальные функции»?

Предотвращайте захват переменных ради ясности и производительности. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Статические локальные функции»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Объявление локальных функций
  2. Замыкания и захваченные переменные
  3. Статические локальные функции
  4. Локальные функции и лямбда-выражения
← Назад к C# Academy