Точка входа в программу представляет функцию, с которой начинается выполнение приложения. Для определения функции как точки входа в приложения, применяются ряд условий:
Эта функция должна применять атрибут [<EntryPoint>]
Последний компилируемый файл - это последний файл в проекте, либо последний файл в списке файлов, которые передаются компилятору при компиляции в командной строке
Эта функция должна принимать один параметр - набор (а точнее массив) строк, через которые в данную функцию можно передать данные при ее вызове. (Например, при запуске приложения из командной строки)
Эта функция должна возвращать число типа int
. Согласно условностям, обычно это 0 - при успешном выполнении, либо любое другое число при неудачном выполнении.
Эта функция должна быть последней функцией в последнем компилируемом файле.
Как правило, эта функция называеся main, но это необязательно. Например, определим в проекте в главном файле программы Program.fs следующий код:
[<EntryPoint>] let main argv = printfn "Функция main" 0
Итак, данная функция применяет атрибут [<EntryPoint>]
(он указывается над определением функции). Она имеет один параметр и возвращает число.
Запустим проект на выполнение с помощью dotnet run:
C:\Users\eugen\fsharp\helloapp>dotnet run Функция main C:\Users\eugen\fsharp\helloapp>
По умолчанию при написании программы нам необязательно определять функцию-точку входа в программу, так как мы можем использовать так называемые программы верхнего уровня или top level statements, когда мы сразу можем вызывать инструкции вне какой-либо функции.
Стоит отметить, что если параметр функции не используется, мы можем, как в общем случае, вместо него указать прочерк:
[<EntryPoint>] let main _ = printfn "Функция main" 0
Теперь обратимся к последнему условию: функция входа в приложение должна быть последней функций (и вообще последним опредлением в файле). То есть мы можем разместить другие конструкции, определения значений, функций, их вызов до функции main:
let sum x y = x + y let message = "Hello F#" printfn $"{message}" [<EntryPoint>] let main _ = printfn "Функция main" 0
Но мы НЕ можем это сделать после определения функции входа в приложение:
[<EntryPoint>] let main _ = printfn "Функция main" 0 let sum x y = x + y let message = "Hello F#" printfn $"{message}"
Но в принципе в этом случае компилятор укажет на ошибку.
Стоит отметить, что если до функции точки входа в приложение идут вызовы других функций, то они также выполняются. В данном случае имеются ввиду вызовы функций верхнего уровня - то есть такие вызовы функций, которые расположены вне других функций. Например, путь у нас будет следующий код программы:
let sum x y = x + y let message = "Hello F#" printfn $"{message}" printfn $"Сумма 1 и 2 равна {sum 1 2}" [<EntryPoint>] let main _ = printfn "Функция main" 0
В данном случае мы получим следующий консольный вывод:
Hello F# Сумма 1 и 2 равна 3 Функция main
Таким образом, мы видим, что все выражения, которые идут до функции main, также были выполнены.
Однако если до функции входа в приложение идут только определения функций без их вызовов, то эти функции не выполняются:
let sum x y = printfn $"Сумма {x} и {y} равна {x + y}" let printMessage _ = printfn "Hello F#" [<EntryPoint>] let main _ = printfn "Функция main" 0
Так, в данном случае будет выполняться только функция main, поскольку именно она является точкой входа в приложения. Соответственно консольный вывод программы:
Функция main
Чтобы выполнить подобные функции, нам надо вызвать их в функции main:
let sum x y = printfn $"Сумма {x} и {y} равна {x + y}" let printMessage _ = printfn "Hello F#" [<EntryPoint>] let main _ = printfn "Функция main" sum 1 2 printMessage() 0
Консольный вывод программы:
Функция main Сумма 1 и 2 равна 3 Hello F#
Выше было показано, как определять точку входа, однако в предыдущих статьях точка входа не использовалась, но код тем не менее выполнялся. Если в коде явным образом не определено функции с атрибутом EntryPoint, то в качестве точки входа используются все привязки значений и функций верхнего уровня, которые определены в последнем компилируемом файле.