Подтвердить что ты не робот

Значения модулей в F # не инициализируются. Зачем?

У меня странное поведение, когда я использовал F #. Когда я использую let binding в модуле, и если значение создается из конструктора, то оно не инициализируется при использовании снаружи. (Я использовал его с С#, используя ModuleName.s2 или ModuleName.f())

//in a module
let s1 = "1" //normal
let s2 = new String('i', 5) //null

let f () =
    s2.Equals("something") //Exception

Это нормальное поведение? Спасибо заранее.

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

4b9b3361

Ответ 1

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

UPDATE

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

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

[<EntryPoint>]
let main _ =
    0

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

ОБНОВЛЕНИЕ 2

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

Ответ 2

По какой-то причине SomeModule.s2 реализуется как свойство (только для чтения), которое возвращает значение невыразимого статического поля <StartupCode$FS>[email protected]. Если вы компилируете в качестве приложения, это поле инициализируется в основном методе. При использовании кода С# этот метод не вызывается, поэтому поле не инициализируется.

Если вы компилируете в качестве библиотеки, код будет таким же, за исключением того, что поле инициализируется в статическом конструкторе класса $Program, поэтому оно должно работать при использовании с С#.

Причиной s1 всегда является оптимизация: компилятор F # понимает его как константу и реализует f() как "1".Equals("something").