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

Сколько выходных параметров будет у функции не имеющей параметров значений

  • автор:

Тест №4 по теме «Программирование»
тест по информатике и икт на тему

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

2) Подпрограмма – это независимая от основной программы группа операторов, оформленная в виде самостоятельной прог-раммной единицы. Она записывается однократно, обращение к ней из основной программы не происходит.

3) Подпрограмма – это повторяющаяся группа операторов, оформленная в виде самостоятельной программной единицы и записанная в отдельный файл.

Правильный ответ – 1.

2. Какие утверждения для подпрограмм верны?

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

Б. О ни улучшают структуру программы, облегчая понимание при разборе.

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

Правильный ответ – 3.

3. Какие параметры называются фактическими?

1) Фактические параметры – это переменные, фиктивно присутствующие в процедуре и определяющие тип и место подстановки фактических параметров, над которыми производятся действия.

2) Фактические параметры – это параметры, которые передаются процедуре при обращении к ней.

3) Фактические параметры – это параметры, которые присутствуют в процедуре.

Правильный ответ – 2.

4. Какие параметры называются формальными?

1) Формальные параметры – это переменные, фиктивно присутствующие в процедуре и определяющие тип и место подстановки фактических параметров, над которыми производятся действия.

2) Формальные параметры – это параметры, которые передаются процедуре при обращении к ней.

3) Формальные параметры – это параметры, которые присутствуют в процедуре.

Правильный ответ – 1.

5. Как связаны между собой формальные и фактические параметры?

1) Число и тип формальных и фактических параметров совпадают с точностью до их следования.

2) Число формальных и фактических параметров совпадают.

3) Типы формальных и фактических параметров могут не совпадать.

Правильный ответ – 1.

6. Какие переменные называются глобальными?

1) Глобальные переменные – это те переменные, которые объявлены в описании основной части, и их могут использовать любые процедуры и функции данной программы.

2) Переменные, описанные внутри подпрограммы, называются глобальными, и они могут быть использованы только внутри данной подпрограммы.

3) Переменные, описанные внутри подпрограммы, называются глобальными, и они могут быть использованы как внутри данной подпрограммы, так и в основной программе.

Правильный ответ – 1.

7. Какие переменные называются локальными?

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

2) Переменные, описанные внутри подпрограммы, называются локальными, и они могут быть использованы только внутри данной подпрограммы.

3) Переменные, описанные внутри подпрограммы, называются локальными, и они могут быть использованы как внутри данной подпрограммы, так и в основной программе.

Правильный ответ – 2.

8. Выберите правильное описание функции.

Правильный ответ – 3.

9. Каковы отличия функции от процедуры?

1) Процедура может иметь несколько значений, а функция только одно (оно и будет ее результатом). Кроме того, в теле функции обязательно должен быть хотя бы один оператор присвоения, где в левой части стоит имя функции, а в правой – ее значение. Иначе значение не будет определено.

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

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

Правильный ответ – 1.

10. Указывается ли тип результата в описании функции?

1) В Quick Basic – нет, в Паскале – да

2) В Quick Basic – да, в Паскале – нет,

Правильный ответ – 1.

11. Что такое рекурсия?

1) Объект, который частично определяется через другие неизвестные объекты, называется – рекурсивным.

2) Объект, который частично определяется через самого себя, называется – рекурсивным.

3) Объект, который частично определяется через другие известные объекты, называется – рекурсивным.

Правильный ответ – 2.

12. Как избавиться от бесконечного обращения подпрограммы к самой себе?

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

2) Требуется наличие оператора цикла в тексте программы, по окончании которого дальнейшее обращение не происходит.

Правильный ответ – 1.

13. Возможно ли задачи, явно не содержащие в себе рекурсию, свести к рекурсивной?

3) Задачи, не содержащие явно в себе рекурсию, невозможно свести к рекурсивным.

Правильный ответ – 2.

14. Что такое область действия переменной?

1) Область действия переменной называется часть программы, где она может быть использована. Область действия переменных определяется местом их объявления.

2) Область действия переменной называется часть программы, где она не может быть использована.

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

Правильный ответ – 1.

15. Может ли локальная переменная быть одновременно глобальной?

1) Да, по отношению к более высокому уровню вложенности.

3) Да, по отношению к вложенным в нее подпрограммам.

Правильный ответ – 3.

16. Как происходит замена формальных параметров на фактические?

1) Формальные параметры заменяются на фактические в произвольном порядке.

2) Формальные параметры заменяются на фактические в порядке их следования.

3) Формальные параметры заменяются на фактические в обратном порядке их следования.

Правильный ответ – 2.

17. Что произойдет при совпадении имен глобальных и локальных переменных?

1) Глобальные переменные отменяют действия локальных переменных.

2) Локальные переменные, в пределах своего действия, отменяют действия глобальных переменных.

3) Локальные переменные отменяют действия глобальных переменных.

Правильный ответ – 2.

18. Возможно ли неоднократное применение процедур и функций?

1) Возможно, не более двух раз.

2) Возможно, не более одного раза .

Функции

Функции – это самостоятельные фрагменты кода, решающие определенную задачу. Каждой функции присваивается уникальное имя, по которому ее можно идентифицировать и «вызвать» в нужный момент.

Язык Swift предлагает достаточно гибкий единый синтаксис функций – от простых C-подобных функций без параметров до сложных методов в стиле Objective-C с локальными и внешними параметрами. Параметры могут служить как для простой инициализации значений внутри функции, так и для изменения внешних переменных после выполнения функции.

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

Объявление и вызов функций

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

У каждой функции должно быть имя, которое отражает решаемую задачу. Чтобы воспользоваться функцией, ее нужно «вызвать», указав имя и входные значения (аргументы), соответствующие типам параметров этой функции. Аргументы функции всегда должны идти в том же порядке, в каком они были указаны при объявлении функции.

В приведенном ниже примере функция называется greet(person:) , потому что это отражает ее задачу – получить имя пользователя и вежливо поздороваться. Для этого задается один входной параметр типа String под названием person , а возвращается тоже значение типа String , но уже содержащее приветствие:

func greet(person: String) -> String

Вся эта информация указана в объявлении функции, перед которым стоит ключевое слово func . Тип возвращаемого значения функции ставится после результирующей стрелки -> (это дефис и правая угловая скобка).

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

print(greet(person: "Anna")) // Выведет "Привет, Anna!" print(greet(person: "Brian")) // Выведет "Привет, Brian!"

Функция greet(person:) вызывается, принимая значение типа String , которое стоит после имени person , например вот так — greet(person: «Anna») . Поскольку функция возвращает значение типа String , вызов функции greet(person:) может быть завернут в вызов для функции print(_:separator:terminator:) , чтобы напечатать полученную строку и увидеть возвращаемое значение (см. выше).

Заметка

У print(_:separator:terminator:) нет ярлыка для первого аргумента, и его другие аргументы являются опциональными, поскольку имеют дефолтное значение (по умолчанию). Эти вариации синтаксиса функции рассматриваются ниже в Ярлыки аргументов и имена параметров функций и Значения по умолчанию для параметров.

Тело функции greet(person:) начинается с объявления новой константы типа String под названием greeting , и устанавливается простое сообщение-приветствие. Затем это приветствие возвращается в точку вызова функции с помощью ключевого слова return . После выполнения оператора return greeting функция завершает свою работу и возвращает текущее значение greeting .

Функцию greet(person:) можно вызывать многократно и с разными входными значениями. В примере выше показано, что будет, если функцию вызвать с аргументом «Anna» и со значением «Brian» . В каждом случае функция возвратит персональное приветствие.

Чтобы упростить код этой функции, можно записать создание сообщения и его возврат в одну строку:

func greetAgain(person: String) -> String < return "Hello again, " + person + "!" >print(greetAgain(person: "Anna")) // Выведет "Hello again, Anna!"

Параметры функции и возвращаемые значения

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

Функции без параметров

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

func sayHelloWorld() -> String < return "hello, world" >print(sayHelloWorld()) // Выведет "hello, world"

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

Функции с несколькими входными параметрами

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

Эта функция принимает два параметра: имя человека и булево значение, приветствовали ли его уже, и возвращает соответствующее приветствие для этого человека:

func greet(person: String, alreadyGreeted: Bool) -> String < if alreadyGreeted < return greetAgain(person: person) >else < return greet(person: person) >> print(greet(person: "Tim", alreadyGreeted: true)) // Выведет "Hello again, Tim!"

Вы вызываете функцию greet(person:alreadyGreeted:) , передавая значение типа String параметру с ярлыком person и булево значение с ярлыком alreadyGreeted , взятое в скобки через запятую. Обратите внимание, что эта функция отличается от функции greet(person:) , которую вы видели в предыдущем разделе. Хотя имена обеих функций начинаются с greet , функция greet(person:alreadyGreeted:) принимает два аргумента, а greet(person:) принимает только один.

Функции, не возвращающие значения

В некоторых случаях функции могут не иметь возвращаемого типа. Вот другая реализация функции greet(person:) , которая выводит свое собственное значение типа String , но не возвращает его:

func greet(person: String) < print("Привет, \(person)!") >greet(person: "Dave") // Выведет "Привет, Dave!"

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

Заметка

Строго говоря, функция greet(person:) все же возвращает значение, хотя оно нигде и не указано. Функции, для которых не задан возвращаемый тип, получают специальный тип Void . По сути, это просто пустой кортеж, т. е. кортеж с нулем элементов, который записывается как () .

Выходное значение функции может быть игнорировано:

func printAndCount(string: String) -> Int < print(string) return string.count >func printWithoutCounting(string: String) < let _ = printAndCount(string: string) >printAndCount(string: "hello, world") // Выведет "hello, world" и возвращает значение 12 printWithoutCounting(string: "hello, world") // Выведет "hello, world", но не возвращает значения

Первая функция, printAndCount(string:) выводит строку, а затем возвращает подсчет символов в виде целого ( Int ). Вторая функция, printWithoutCounting(string:) вызывает первую, но игнорирует ее возвращаемое значение. При вызове второй функции первая функция по-прежнему печатает сообщение, но ее возвращаемое значение не используется.

Заметка

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

Функции, возвращающие несколько значений

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

В следующем примере объявлена функция minMax(array:) , которая ищет минимальный и максимальный элементы в массиве типа Int :

func minMax(array: [Int]) -> (min: Int, max: Int) < var currentMin = array[0] var currentMax = array[0] for value in array[1..else if value > currentMax < currentMax = value >> return (currentMin, currentMax) >

Функция minMax(array:) возвращает кортеж из двух значений типа Int . Этим значениям присвоены имена min и max , чтобы к ним можно было обращаться при запросе возвращаемого типа функции.

Тело функции minMax(array:) начинается с инициализации двух рабочих переменных currentMin и currentMax значением первого целого элемента в массиве. Затем функция последовательно проходит по всем остальным значениям в массиве и сравнивает их со значениями currentMin и currentMax соответственно. И наконец, самое маленькое и самое большое значения возвращаются внутри кортежа типа Int .

Так как имена элементов кортежа указаны в возвращаемом типе функции, к ним можно обращаться через точку и считывать значения:

let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) print("min is \(bounds.min) and max is \(bounds.max)") // Выведет "min is -6 and max is 109"

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

Опциональный кортеж как возвращаемый тип

Если возвращаемый из функции кортеж может иметь «пустое значение», то его следует объявить как опциональный кортеж, т. е. кортеж, который может равняться nil . Чтобы сделать возвращаемый кортеж опциональным, нужно поставить вопросительный знак после закрывающей скобки: (Int, Int)? или (String, Int, Bool)? .

Заметка

Кортеж-опционал вида (Int, Int)? — это не то же самое, что кортеж, содержащий опционалы: (Int?, Int?) . Кортеж-опционал сам является опционалом, но не обязан состоять из опциональных значений.

Функция minMax(array:) выше возвращает кортеж из двух значений типа Int , однако не проверяет корректность передаваемого массива. Если аргумент array содержит пустой массив, для которого count равно 0 , функция minMax в том виде, в каком она приведена выше, выдаст ошибку выполнения, когда попытается обратиться к элементу array[0] .

Для устранения этого недочета перепишем функцию minMax(array:) так, чтобы она возвращала кортеж-опционал, который в случае пустого массива примет значение nil :

func minMax(array: [Int]) -> (min: Int, max: Int)? < if array.isEmpty < return nil >var currentMin = array[0] var currentMax = array[0] for value in array[1.. else if value > currentMax < currentMax = value >> return (currentMin, currentMax) >

Чтобы проверить, возвращает ли эта версия функции minMax(array:) фактическое значение кортежа или nil , можно использовать привязку опционала:

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) < print("min is \(bounds.min) and max is \(bounds.max)") >// Выведет "min is -6 and max is 109"

Функции с неявным возвращаемым значением

Если тело функции состоит из единственного выражения, то функция неявно возвращает это выражение. Например, обе функции в примере ниже имеют одно и то же поведение:

func greeting(for person: String) -> String < "Привет, " + person + "!" >print(greeting(for: "Дейв")) // Выведет "Привет, Дейв!" func anotherGreeting(for person: String) -> String < return "Привет, " + person + "!" >print(anotherGreeting(for: "Дейв")) // Выведет "Привет, Дейв!"

Поведение функции greeting(for:) заключается в том, чтобы просто вернуть приветственное сообщение, что означает, что мы можем использовать сокращенную запись этой функции. Функция anotherGreeting(for:) возвращает то же самое приветственное сообщение, используя ключевое слово return . Таким образом, если вы пишите функцию, которая состоит из одного лишь возвращаемого значения, то вы можете опустить слово return .

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

Заметка

Код, который вы написали с неявным возвращаемым значением должен иметь это самое возвращаемое значение. Например, вы не можете использовать print(13) как неявное возвращаемые значения. Однако вы можете использовать функцию, которая никогда не возвращает значение, например, fatalError(«Oh no!») , в качестве неявного возвращаемого значения, потому что Swift знает, что неявного возврата не происходит.

Ярлыки аргументов и имена параметров функций

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

func someFunction(firstParameterName: Int, secondParameterName: Int) < // Внутри тела функции firstParameterName и secondParameterName // ссылаются на значения аргументов, первого и второго параметров. >someFunction(firstParameterName: 1, secondParameterName: 2)

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

Указываем ярлыки аргументов

Вы пишете ярлык аргумента перед именем параметра через пробел:

func someFunction(argumentLabel parameterName: Int) < // В теле функции parameterName относится к значению аргумента // для этого параметра. >

Вот вариант функции greet(person:) , которая принимает имя человека и его родной город, затем возвращает приветствие:

func greet(person: String, from hometown: String) -> String < return "Hello \(person)! Glad you could visit from \(hometown)." >print(greet(person: "Bill", from: "Cupertino")) // Выводит "Hello Bill! Glad you could visit from Cupertino."

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

Пропуск ярлыков аргумента

Если вы не хотите использовать имя параметра в качестве ярлыка аргумента — используйте подчеркивание ( _ ) вместо явного ярлыка аргумента для этого параметра.

func someFunction(_ firstParameterName: Int, secondParameterName: Int) < // В теле функции firstParameterName и secondParameterName // ссылаются на значения аргументов для первого и второго параметров. >someFunction(1, secondParameterName: 2) 

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

Значения по умолчанию для параметров

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

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) < // Если вы пропускаете второй аргумент при вызове функции, то // значение parameterWithDefault будет равняться 12 внутри тела функции. >someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault равен 6 someFunction(parameterWithoutDefault: 4) // parameterWithDefault равен 12

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

Вариативные параметры

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

Значения, переданные через вариативный параметр, доступны внутри функции в виде массива соответствующего типа. Например, вариативный параметр numbers типа Double. доступен внутри функции в виде массива-константы numbers типа [Double] .

В приведенном ниже примере вычисляется среднее арифметическое (или же среднее) последовательности чисел, имеющей произвольную длину:

func arithmeticMean(_ numbers: Double. ) -> Double < var total: Double = 0 for number in numbers < total += number >return total / Double(numbers.count) > arithmeticMean(1, 2, 3, 4, 5) // возвращает 3.0, что является средним арифметическим этих пяти чисел arithmeticMean(3, 8.25, 18.75) // возвращает 10.0, что является средним арифметическим этих трех чисел

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

Сквозные параметры

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

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

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

Заметка

Сквозные параметры не могут иметь значения по умолчанию, а вариативные параметры не могут быть сквозными, с ключевым словом inout .

Вот пример функции под названием swapTwoInts(_:_:) , у которой есть два сквозных целочисленных параметра – a и b :

func swapTwoInts(_ a: inout Int, _ b: inout Int)

Функция swapTwoInts(_:_:) просто меняет значение переменной b на значение a , а значение a – на значение b . Для этого функция сохраняет значение a в локальной константе temporaryA , присваивает значение b переменной a , а затем присваивает значение temporaryA переменной b .

Вы можете вызвать функцию swapTwoInts (_: _:) с двумя переменными типа Int , чтобы поменять их значения. Обратите внимание, что имена someInt и anotherInt начинаются с амперсанда, когда они передаются в swapTwoInts (_: _:) функции:

var someInt = 3 var anotherInt = 107 swapTwoInts(&someInt, &anotherInt) print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // Выведет "someInt is now 107, and anotherInt is now 3"

В вышеприведенном примере видно, что исходные значения переменных someInt и anotherInt изменены функцией swapTwoInts (_: _:) , несмотря на то, что изначально они были объявлены за ее пределами.

Заметка

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

Функциональные типы

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

func addTwoInts(a: Int, _ b: Int) -> Int < return a + b >func multiplyTwoInts(a: Int, _ b: Int) -> Int

В данном примере объявлены две простые математические функции – addTwoInts и multiplyTwoInts . Каждая из этих функций принимает два значения типа Int и возвращает одно значение типа Int , содержащее результат математической операции.

Обе функции имеют тип (Int, Int) -> Int . Эта запись означает следующее:

«функция с двумя параметрами типа Int , возвращающая значение типа Int «.

Вот еще один пример, но уже функции без параметров и возвращаемого значения:

func printHelloWorld()

Эта функция имеет тип () -> Void , т. е. «функция без параметров, которая возвращает Void «.

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

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

var mathFunction: (Int, Int) -> Int = addTwoInts

Эта запись означает следующее:

«Объявить переменную mathFunction , имеющую тип «функция, принимающая два значения типа Int , и возвращающая одно значение типа Int «. Присвоить этой новой переменной указатель на функцию addTwoInts «.

Функция addTwoInts имеет тот же тип, что и переменная mathFunction , поэтому с точки зрения языка Swift такое присваивание корректно.

Теперь функцию можно вызывать с помощью переменной mathFunction :

print("Result: \(mathFunction(2, 3))") // Выведет "Result: 5"

Той же переменной можно присвоить и другую функцию такого же типа – аналогично нефункциональным типам:

mathFunction = multiplyTwoInts print("Result: \(mathFunction(2, 3))") // Выведет "Result: 6"

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

let anotherMathFunction = addTwoInts // для константы anotherMathFunction выведен тип (Int, Int) -> Int

Функциональные типы как типы параметров

Функциональные типы наподобие (Int, Int) -> Int могут быть типами параметров другой функции. Это позволяет определять некоторые аспекты реализации функции непосредственно во время ее вызова.

Следующий код печатает на экране результаты работы приведенных выше математических функций:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) < print("Result: \(mathFunction(a, b))") >printMathResult(addTwoInts, 3, 5) // Выведет "Result: 8"

В этом примере объявлена функция printMathResult(_:_:_:) , у которой есть три параметра. Первый параметр под названием mathFunction имеет тип (Int, Int) -> Int. Соответственно, аргументом этого параметра может быть любая функция такого же типа. Второй и третий параметры называются a и b и относятся к типу Int . Они служат для передачи двух входных значений для математической функции.

При вызове printMathResult(_:_:_:) получает в качестве входных данных функцию addTwoInts(_:_:) и два целочисленных значения 3 и 5 . Затем она вызывает переданную функцию со значениями 3 и 5 , а также выводит на экран результат 8 .

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

Функциональные типы как возвращаемые типы

Функциональный тип можно сделать возвращаемым типом другой функции. Для этого нужно записать полный функциональный тип сразу же после возвратной стрелки ( -> ) в возвращаемой функции.

В следующем примере объявлены две простые функции – stepForward(_:) и stepBackward(_:) . Функция stepForward(_:) возвращает входное значение, увеличенное на единицу, а функция stepBackward(_:) – уменьшенное на единицу. Обе функции имеют тип (Int) -> Int :

func stepForward(_ input: Int) -> Int < return input + 1 >func stepBackward(_ input: Int) -> Int

Следующая функция под названием chooseStepFunction(backward:) имеет возвращаемый тип (Int) -> Int . Функция chooseStepFunction(backward:) возвращает функцию stepForward(_:) или функцию stepBackward(_:) в зависимости от значения логического параметра backward :

func chooseStepFunction(backward: Bool) -> (Int) -> Int

Теперь с помощью chooseStepFunction(backward:) можно получать функцию, которая будет сдвигать значение влево или вправо:

var currentValue = 3 let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) // moveNearerToZero ссылается на функцию stepBackward()

В предыдущем примере мы определяли, нужно ли прибавить или отнять единицу, чтобы последовательно приблизить переменную currentValue к нулю. Изначально currentValue имеет значение 3 , т. е. сравнение currentValue > 0 даст true , а функция chooseStepFunction(backward:) , соответственно, возвратит функцию stepBackward(_:) . Указатель на возвращаемую функцию хранится в константе moveNearerToZero .

Так как moveNearerToZero теперь ссылается на нужную функцию, можно использовать эту константу для отсчета до нуля:

print("Counting to zero:") // Counting to zero: while currentValue != 0 < print("\(currentValue). ") currentValue = moveNearerToZero(currentValue) >print("zero!") // 3. // 2. // 1. // zero!

Вложенные функции

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

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

Приведенный выше пример с функцией chooseStepFunction(backward:) можно переписать со вложенными функциями:

func chooseStepFunction(backward: Bool) -> (Int) -> Int < func stepForward(input: Int) ->Int < return input + 1 >func stepBackward(input: Int) -> Int < return input - 1 >return backward ? stepBackward : stepForward > var currentValue = -4 let moveNearerToZero = chooseStepFunction(backward: currentValue > 0) // moveNearerToZero теперь ссылается на вложенную функцию stepForward() while currentValue != 0 < print("\(currentValue). ") currentValue = moveNearerToZero(currentValue) >print("zero!") // -4. // -3. // -2. // -1. // zero!

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Сколько выходных параметров будет у функции не имеющей параметров значений

SQL-функции выполняют произвольный список операторов SQL и возвращают результат последнего запроса в списке. В простом случае (не с множеством) будет возвращена первая строка результата последнего запроса. (Помните, что понятие « первая строка » в наборе результатов с несколькими строками определено точно, только если присутствует ORDER BY .) Если последний запрос вообще не вернёт строки, будет возвращено значение NULL.

Кроме того, можно объявить SQL-функцию как возвращающую множество (то есть, несколько строк), указав в качестве возвращаемого типа функции SETOF некий_тип , либо объявив её с указанием RETURNS TABLE( столбцы ) . В этом случае будут возвращены все строки результата последнего запроса. Подробнее это описывается ниже.

Тело SQL-функции должно представлять собой список SQL-операторов, разделённых точкой с запятой. Точка с запятой после последнего оператора может отсутствовать. Если только функция не объявлена как возвращающая void , последним оператором должен быть SELECT , либо INSERT , UPDATE или DELETE с предложением RETURNING .

Любой набор команд на языке SQL можно скомпоновать вместе и обозначить как функцию. Помимо запросов SELECT , эти команды могут включать запросы, изменяющие данные ( INSERT , UPDATE и DELETE ), а также другие SQL-команды. (В SQL -функциях нельзя использовать команды управления транзакциями, например COMMIT , SAVEPOINT , и некоторые вспомогательные команды, в частности VACUUM .) Однако последней командой должна быть SELECT или команда с предложением RETURNING , возвращающая результат с типом возврата функции. Если же вы хотите определить функцию SQL, выполняющую действия, но не возвращающую полезное значение, вы можете объявить её как возвращающую тип void . Например, эта функция удаляет строки с отрицательным жалованьем из таблицы emp :

CREATE FUNCTION clean_emp() RETURNS void AS ' DELETE FROM emp WHERE salary < 0; ' LANGUAGE SQL; SELECT clean_emp(); clean_emp ----------- (1 row)

Примечание

Прежде чем начинается выполнение команд, разбирается всё тело SQL-функции. Когда SQL-функция содержит команды, модифицирующие системные каталоги (например, CREATE TABLE ), действие таких команд не будет видимо на стадии анализа последующих команд этой функции. Так, например, команды CREATE TABLE foo (. ); INSERT INTO foo VALUES(. ); не будут работать, как ожидается, если их упаковать в одну SQL-функцию, так как foo не будет существовать к моменту разбору команды INSERT . В подобных ситуациях вместо SQL-функции рекомендуется использовать PL/PgSQL .

Синтаксис команды CREATE FUNCTION требует, чтобы тело функции было записано как строковая константа. Обычно для этого удобнее всего заключать строковую константу в доллары (см. Подраздел 4.1.2.4). Если вы решите использовать обычный синтаксис с заключением строки в апострофы, вам придётся дублировать апострофы ( ' ) и обратную косую черту ( \ ) (предполагается синтаксис спецпоследовательностей) в теле функции (см. Подраздел 4.1.2.1).

35.4.1. Аргументы SQL -функций

К аргументам SQL-функции можно обращаться в теле функции по именам или номерам. Ниже приведены примеры обоих вариантов.

Чтобы использовать имя, объявите аргумент функции как именованный, а затем просто пишите это имя в теле функции. Если имя аргумента совпадает с именем какого-либо столбца в текущей SQL-команде внутри функции, имя столбца будет иметь приоритет. Чтобы всё же перекрыть имя столбца, дополните имя аргумента именем самой функции, то есть запишите его в виде имя_функции . имя_аргумента . (Если и это имя будет конфликтовать с полным именем столбца, снова выиграет имя столбца. Неоднозначности в этом случае вы можете избежать, выбрав другой псевдоним для таблицы в SQL-команде.)

Старый подход с нумерацией позволяет обращаться к аргументам, применяя запись $ n : $1 обозначает первый аргумент, $2 — второй и т. д. Это будет работать и в том случае, если данному аргументу назначено имя.

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

Аргументы SQL-функции могут использоваться только как значения данных, но не как идентификаторы. Например, это приемлемо:

INSERT INTO mytable VALUES ($1);

а это не будет работать:

INSERT INTO $1 VALUES (42);

Примечание

Возможность обращаться к аргументам SQL-функций по именам появилась в PostgreSQL 9.2. В функциях, которые должны работать со старыми серверами, необходимо применять запись $ n .

35.4.2. Функции SQL с базовыми типами

Простейшая возможная функция SQL не имеет аргументов и просто возвращает базовый тип, например integer :

CREATE FUNCTION one() RETURNS integer AS $$ SELECT 1 AS result; $$ LANGUAGE SQL; -- Альтернативная запись строковой константы: CREATE FUNCTION one() RETURNS integer AS ' SELECT 1 AS result; ' LANGUAGE SQL; SELECT one(); one ----- 1

Заметьте, что мы определили псевдоним столбца в теле функции для её результата (дали ему имя result ), но этот псевдоним не виден снаружи функции. Вследствие этого, столбец результата получил имя one , а не result .

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

CREATE FUNCTION add_em(x integer, y integer) RETURNS integer AS $$ SELECT x + y; $$ LANGUAGE SQL; SELECT add_em(1, 2) AS answer; answer -------- 3

Мы также можем отказаться от имён аргументов и обращаться к ним по номерам:

CREATE FUNCTION add_em(integer, integer) RETURNS integer AS $$ SELECT $1 + $2; $$ LANGUAGE SQL; SELECT add_em(1, 2) AS answer; answer -------- 3

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

CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS integer AS $$ UPDATE bank SET balance = balance - debit WHERE accountno = tf1.accountno; SELECT 1; $$ LANGUAGE SQL;

Пользователь может выполнить эту функцию, чтобы дебетовать счёт 17 на 100 долларов, так:

SELECT tf1(17, 100.0);

В этом примере мы выбрали имя accountno для первого аргумента, но это же имя имеет столбец в таблице bank . В команде UPDATE имя accountno относится к столбцу bank.accountno , так для обращения к аргументу нужно записать tf1.accountno . Конечно, мы могли бы избежать этого, выбрав другое имя для аргумента.

На практике обычно желательно получать от функции более полезный результат, чем константу 1, поэтому более реалистично такое определение:

CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS integer AS $$ UPDATE bank SET balance = balance - debit WHERE accountno = tf1.accountno; SELECT balance FROM bank WHERE accountno = tf1.accountno; $$ LANGUAGE SQL;

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

CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS integer AS $$ UPDATE bank SET balance = balance - debit WHERE accountno = tf1.accountno RETURNING balance; $$ LANGUAGE SQL;

35.4.3. Функции SQL со сложными типами

В функциях с аргументами составных типов мы должны указывать не только, какой аргумент, но и какой атрибут (поле) этого аргумента нам нужен. Например, предположим, что emp — таблица, содержащая данные работников, и это же имя составного типа, представляющего каждую строку таблицы. Следующая функция double_salary вычисляет, каким было бы чьё-либо жалование в случае увеличения вдвое:

CREATE TABLE emp ( name text, salary numeric, age integer, cubicle point ); INSERT INTO emp VALUES ('Bill', 4200, 45, '(2,1)'); CREATE FUNCTION double_salary(emp) RETURNS numeric AS $$ SELECT $1.salary * 2 AS salary; $$ LANGUAGE SQL; SELECT name, double_salary(emp.*) AS dream FROM emp WHERE emp.cubicle ~= point '(2,1)'; name | dream ------+------- Bill | 8400

Обратите внимание на запись $1.salary позволяющую выбрать одно поле из значения строки аргумента. Также заметьте, что в вызывающей команде SELECT указание имя_таблицы .* выбирает всю текущую строку таблицы как составное значение. На строку таблицы можно сослаться и просто по имени таблицы, например так:

SELECT name, double_salary(emp) AS dream FROM emp WHERE emp.cubicle ~= point '(2,1)';

Однако это использование считается устаревшим, так как провоцирует путаницу. (Подробнее эти две записи составных значений строки таблицы описаны в Подразделе 8.16.5.)

Иногда бывает удобно образовать составное значение аргумента на лету. Это позволяет сделать конструкция ROW . Например, так можно изменить данные, передаваемые функции:

SELECT name, double_salary(ROW(name, salary*1.1, age, cubicle)) AS dream FROM emp;

Также возможно создать функцию, возвращающую составной тип. Например, эта функция возвращает одну строку emp :

CREATE FUNCTION new_emp() RETURNS emp AS $$ SELECT text 'None' AS name, 1000.0 AS salary, 25 AS age, point '(2,2)' AS cubicle; $$ LANGUAGE SQL;

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

Учтите два важных требования относительно определения функции:

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

Вы должны привести выражения в соответствие с определением составного типа, либо вы получите такие ошибки:

 ERROR: function declared to return emp returns varchar instead of text at column 1 

Ту же функцию можно определить другим способом:

CREATE FUNCTION new_emp() RETURNS emp AS $$ SELECT ROW('None', 1000.0, 25, '(2,2)')::emp; $$ LANGUAGE SQL;

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

Мы можем вызывать эту функцию напрямую, либо указав её в выражении значения:

SELECT new_emp(); new_emp -------------------------- (None,1000.0,25,"(2,2)")

либо обратившись к ней, как к табличной функции:

SELECT * FROM new_emp(); name | salary | age | cubicle ------+--------+-----+--------- None | 1000.0 | 25 | (2,2)

Второй способ более подробно описан в Подразделе 35.4.7.

Когда используется функция, возвращающая составной тип, может возникнуть желание получить из её результата только одно поле (атрибут). Это можно сделать, применяя такую запись:

SELECT (new_emp()).name; name ------ None

Дополнительные скобки необходимы во избежание неоднозначности при разборе запроса. Если вы попытаетесь выполнить запрос без них, вы получите ошибку:

SELECT new_emp().name; ERROR: syntax error at or near "." LINE 1: SELECT new_emp().name; ^

(ОШИБКА: синтаксическая ошибка (примерное положение: "."))

Функциональную запись также можно использовать и для извлечения атрибутов:

SELECT name(new_emp()); name ------ None

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

Ещё один вариант использования функции, возвращающей составной тип, заключается в передаче её результата другой функции, которая принимает этот тип строки на вход:

CREATE FUNCTION getname(emp) RETURNS text AS $$ SELECT $1.name; $$ LANGUAGE SQL; SELECT getname(new_emp()); getname --------- None (1 row)

35.4.4. Функции SQL с выходными параметрами

Альтернативный способ описать результаты функции — определить её с выходными параметрами, как в этом примере:

CREATE FUNCTION add_em (IN x int, IN y int, OUT sum int) AS 'SELECT x + y' LANGUAGE SQL; SELECT add_em(3,7); add_em -------- 10 (1 row)

Это по сути не отличается от версии add_em , показанной в Подразделе 35.4.2. Действительная ценность выходных параметров в том, что они позволяют удобным способом определить функции, возвращающие несколько столбцов. Например:

CREATE FUNCTION sum_n_product (x int, y int, OUT sum int, OUT product int) AS 'SELECT x + y, x * y' LANGUAGE SQL; SELECT * FROM sum_n_product(11,42); sum | product -----+--------- 53 | 462 (1 row)

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

CREATE TYPE sum_prod AS (sum int, product int); CREATE FUNCTION sum_n_product (int, int) RETURNS sum_prod AS 'SELECT $1 + $2, $1 * $2' LANGUAGE SQL;

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

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

DROP FUNCTION sum_n_product (x int, y int, OUT sum int, OUT product int); DROP FUNCTION sum_n_product (int, int);

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

35.4.5. Функции SQL с переменным числом аргументов

Функции SQL могут быть объявлены как принимающие переменное число аргументов, с условием, что все « необязательные » аргументы имеют один тип данных. Необязательные аргументы будут переданы такой функции в виде массива. Для этого в объявлении функции последний параметр помечается как VARIADIC ; при этом он должен иметь тип массива. Например:

CREATE FUNCTION mleast(VARIADIC arr numeric[]) RETURNS numeric AS $$ SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i); $$ LANGUAGE SQL; SELECT mleast(10, -1, 5, 4.4); mleast -------- -1 (1 row)

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

SELECT mleast(ARRAY[10, -1, 5, 4.4]); -- это не будет работать

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

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

SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);

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

Также указание VARIADIC даёт единственную возможность передать пустой массив функции с переменными параметрами, например, так:

SELECT mleast(VARIADIC ARRAY[]::numeric[]);

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

Элементы массива, создаваемые из переменных параметров, считаются не имеющими собственных имён. Это означает, что передать функции с переменными параметрами именованные аргументы нельзя (см. Раздел 4.3), если только при вызове не добавлено VARIADIC . Например, этот вариант будет работать:

SELECT mleast(VARIADIC arr => ARRAY[10, -1, 5, 4.4]);

А эти варианты нет:

SELECT mleast(arr => 10); SELECT mleast(arr => ARRAY[10, -1, 5, 4.4]);

35.4.6. Функции SQL со значениями аргументов по умолчанию

Функции могут быть объявлены со значениями по умолчанию для некоторых или всех входных аргументов. Значения по умолчанию подставляются, когда функция вызывается с недостаточным количеством фактических аргументов. Так как аргументы можно опускать только с конца списка фактических аргументов, все параметры после параметра со значением по умолчанию также получат значения по умолчанию. (Хотя запись с именованными аргументами могла бы ослабить это ограничение, оно всё же остаётся в силе, чтобы позиционные ссылки на аргументы оставались действительными.) Независимо от того, используете вы эту возможность или нет, она требует осторожности при вызове функций в базах данных, где одни пользователи не доверяют другим; см. Раздел 10.3.

CREATE FUNCTION foo(a int, b int DEFAULT 2, c int DEFAULT 3) RETURNS int LANGUAGE SQL AS $$ SELECT $1 + $2 + $3; $$; SELECT foo(10, 20, 30); foo ----- 60 (1 row) SELECT foo(10, 20); foo ----- 33 (1 row) SELECT foo(10); foo ----- 15 (1 row) SELECT foo(); -- не работает из-за отсутствия значения по умолчанию для первого аргумента ERROR: function foo() does not exist

(ОШИБКА: функция foo() не существует) Вместо ключевого слова DEFAULT можно использовать знак = .

35.4.7. Функции SQL , порождающие таблицы

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

CREATE TABLE foo (fooid int, foosubid int, fooname text); INSERT INTO foo VALUES (1, 1, 'Joe'); INSERT INTO foo VALUES (1, 2, 'Ed'); INSERT INTO foo VALUES (2, 1, 'Mary'); CREATE FUNCTION getfoo(int) RETURNS foo AS $$ SELECT * FROM foo WHERE fooid = $1; $$ LANGUAGE SQL; SELECT *, upper(fooname) FROM getfoo(1) AS t1; fooid | foosubid | fooname | upper -------+----------+---------+------- 1 | 1 | Joe | JOE (1 row)

Как показывает этот пример, мы можем работать со столбцами результата функции так же, как если бы это были столбцы обычной таблицы.

Заметьте, что мы получаем из данной функции только одну строку. Это объясняется тем, что мы не использовали указание SETOF . Оно описывается в следующем разделе.

35.4.8. Функции SQL , возвращающие множества

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

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

CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$ SELECT * FROM foo WHERE fooid = $1; $$ LANGUAGE SQL; SELECT * FROM getfoo(1) AS t1;

Тогда в ответ мы получим:

fooid | foosubid | fooname -------+----------+--------- 1 | 1 | Joe 1 | 2 | Ed (2 rows)

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

CREATE TABLE tab (y int, z int); INSERT INTO tab VALUES (1, 2), (3, 4), (5, 6), (7, 8); CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int) RETURNS SETOF record AS $$ SELECT $1 + tab.y, $1 * tab.y FROM tab; $$ LANGUAGE SQL; SELECT * FROM sum_n_product_with_tab(10); sum | product -----+--------- 11 | 10 13 | 30 15 | 50 17 | 70 (4 rows)

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

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

SELECT * FROM nodes; name | parent -----------+-------- Top | Child1 | Top Child2 | Top Child3 | Top SubChild1 | Child1 SubChild2 | Child1 (6 rows) CREATE FUNCTION listchildren(text) RETURNS SETOF text AS $$ SELECT name FROM nodes WHERE parent = $1 $$ LANGUAGE SQL STABLE; SELECT * FROM listchildren('Top'); listchildren -------------- Child1 Child2 Child3 (3 rows) SELECT name, child FROM nodes, LATERAL listchildren(name) AS child; name | child --------+----------- Top | Child1 Top | Child2 Top | Child3 Child1 | SubChild1 Child1 | SubChild2 (5 rows)

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

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

SELECT listchildren('Top'); listchildren -------------- Child1 Child2 Child3 (3 rows) SELECT name, listchildren(name) FROM nodes; name | listchildren --------+-------------- Top | Child1 Top | Child2 Top | Child3 Child1 | SubChild1 Child1 | SubChild2 (5 rows)

Заметьте, что в последней команде SELECT для Child2 , Child3 и т. д. строки не выдаются. Это происходит потому, что listchildren возвращает пустое множество для этих аргументов, так что строки результата не генерируются. Это же поведение мы получаем при внутреннем соединении с результатом функции с применением LATERAL .

Примечание

Если последняя команда функции — INSERT , UPDATE или DELETE с RETURNING , эта команда будет всегда выполняться до завершения, даже если функция не объявлена с указанием SETOF или вызывающий запрос не выбирает все строки результата. Все дополнительные строки, выданные предложением RETURNING , просто игнорируются, но соответствующие изменения в таблице всё равно произойдут (и будут завершены до выхода из функции).

Примечание

Ключевая проблема использования функций, возвращающих множества, в списке выборки, а не в предложении FROM , заключается в том, что при вызове в одном списке выборки нескольких таких функций, результат будет не вполне разумным. (На самом деле, если вы сделаете это, вы получите выходные строки в количестве, равном наименьшему общему кратному чисел строк, которые будут выданы всеми функциями, возвращающими множества.) Синтаксис LATERAL даёт более ожидаемые результаты при вызове нескольких таких функций и поэтому рекомендуется использовать его.

35.4.9. Функции SQL , возвращающие таблицы ( TABLE )

Есть ещё один способ объявить функцию, возвращающую множества, — использовать синтаксис RETURNS TABLE( столбцы ) . Это равнозначно использованию одного или нескольких параметров OUT с объявлением функции как возвращающей SETOF record (или SETOF тип единственного параметра, если это применимо). Этот синтаксис описан в последних версиях стандарта SQL, так что этот вариант может быть более портируемым, чем SETOF .

Например, предыдущий пример с суммой и произведением можно также переписать так:

CREATE FUNCTION sum_n_product_with_tab (x int) RETURNS TABLE(sum int, product int) AS $$ SELECT $1 + tab.y, $1 * tab.y FROM tab; $$ LANGUAGE SQL;

Запись RETURNS TABLE не позволяет явно указывать OUT и INOUT для параметров — все выходные столбцы необходимо записать в списке TABLE .

35.4.10. Полиморфные функции SQL

Функции SQL могут быть объявлены как принимающие и возвращающие полиморфные типы anyelement , anyarray , anynonarray , anyenum и anyrange . За более подробным объяснением полиморфизма функций обратитесь к Подразделу 35.2.5. В следующем примере полиморфная функция make_array создаёт массив из двух элементов произвольных типов:

CREATE FUNCTION make_array(anyelement, anyelement) RETURNS anyarray AS $$ SELECT ARRAY[$1, $2]; $$ LANGUAGE SQL; SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray; intarray | textarray ----------+----------- | (1 row)

Обратите внимание на приведение типа 'a'::text , определяющее, что аргумент имеет тип text . Оно необходимо, если аргумент задаётся просто строковой константой, так как иначе он будет воспринят как имеющий тип unknown , а массив типов unknown является недопустимым. Без этого приведения вы получите такую ошибку:

 ERROR: could not determine polymorphic type because input has type "unknown" 

(ОШИБКА: не удалось определить полиморфный тип, так как входные аргументы имеют тип "unknown")

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

CREATE FUNCTION is_greater(anyelement, anyelement) RETURNS boolean AS $$ SELECT $1 > $2; $$ LANGUAGE SQL; SELECT is_greater(1, 2); is_greater ------------ f (1 row) CREATE FUNCTION invalid_func() RETURNS anyelement AS $$ SELECT 1; $$ LANGUAGE SQL; ERROR: cannot determine result data type DETAIL: A function returning a polymorphic type must have at least one polymorphic argument.

(ОШИБКА: не удалось определить тип результата; ПОДРОБНОСТИ: Функция, возвращающая полиморфный тип, должна иметь минимум один полиморфный аргумент.)

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

CREATE FUNCTION dup (f1 anyelement, OUT f2 anyelement, OUT f3 anyarray) AS 'select $1, array[$1,$1]' LANGUAGE SQL; SELECT * FROM dup(22); f2 | f3 ----+--------- 22 | (1 row)

Полиморфизм также можно применять с функциями с переменными параметрами. Например:

CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$ SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i); $$ LANGUAGE SQL; SELECT anyleast(10, -1, 5, 4); anyleast ---------- -1 (1 row) SELECT anyleast('abc'::text, 'def'); anyleast ---------- abc (1 row) CREATE FUNCTION concat_values(text, VARIADIC anyarray) RETURNS text AS $$ SELECT array_to_string($2, $1); $$ LANGUAGE SQL; SELECT concat_values('|', 1, 4, 2); concat_values --------------- 1|4|2 (1 row)

35.4.11. Функции SQL с правилами сортировки

Когда функция SQL принимает один или несколько параметров сортируемых типов данных, правило сортировки определяется при каждом вызове функции, в зависимости от правил сортировки, связанных с фактическими аргументами, как описано в Разделе 22.2. Если правило сортировки определено успешно (то есть не возникло конфликтов между неявно установленными правилами сортировки аргументов), оно неявно назначается для всех сортируемых параметров. Выбранное правило будет определять поведение операций, связанных с сортировкой, в данной функции. Например, для показанной выше функции anyleast , результат

SELECT anyleast('abc'::text, 'ABC');

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

SELECT anyleast('abc'::text, 'ABC' COLLATE "C");

С другой стороны, если вы хотите, чтобы функция работала с определённым правилом сортировки, вне зависимости от того, с каким она была вызвана, вставьте предложения COLLATE где требуется в определении функции. Эта версия anyleast всегда будет сравнивать строки по правилам локали en_US :

CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$ SELECT min($1[i] COLLATE "en_US") FROM generate_subscripts($1, 1) g(i); $$ LANGUAGE SQL;

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

Если для фактических аргументов не удаётся определить общее правило сортировки, функция SQL считает, что им назначено правило сортировки по умолчанию для их типа данных (обычно это то же правило сортировки, что определено по умолчанию для базы данных, но оно может быть и другим для параметров доменных типов).

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

Пред. Наверх След.
35.3. Пользовательские функции Начало 35.5. Перегрузка функций

Сколько выходных параметров будет у функции, не имеющей параметров значений?

хмара це1) велике текстове поле2) деякий сервер, де зберігаються дані та програми, які використовують користувачі за допомогою глобальної мережі3) про … грама для роботи з текстовою інформацією 4) інший варіант ​

Завдання 1 Рядки тексту перемішані між собою, потрібно встановити рядки тексту у правильному порядку один за всіх, а дві краще. тихіше їдеш, один раз … відріж. сім разів відміряй, то і поїж з охотою. попрацюєш до поту, далі будеш. одна голова добре, краще, ніж добра сварка. поганий мир кращий, всі за одного.

Переведи число 59 из десятичной системы счисления в двоичную и шестнадцатеричную. Запиши ответы в текстовые поля внизу. Для записи шестнадцатеричных ц … ифр используй латиницу. Число 59 в двоичной системе счисления равно Число 59 в шестнадцатеричной системе счисления равно

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

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