Понимание конструкторов типа F # - PullRequest
8 голосов
/ 15 февраля 2011

Я пытаюсь создать сложный тип, и мне нужно во время строительства выполнить некоторые действия.Итак, я начал писать свой код:

type public MyType =
   val private myvar: int
   val private myvar2: string
   (* ...Some val declarations... *)
   new () = {
      (* The default ctor makes something *)
   }
   new (ctorpar: AnotherType) = {
      myvar = 1;
      myvar2 = "Hello";
      (* Other assignments in the form var = val *)
      (* Here I would like to start a cycle in order *)
      for i in ctorpar.array do
         (* Do something *) (* ERROR *)
   }

Хорошо, при попытке поместить for или что-то еще из назначения компилятор сходит с ума.Я предполагаю следующее: Синтаксис для нового соответствует синтаксису Вычислительных выражений, или, лучше, новый является вычислительным выражением (я подразумеваю это из-за фигурных скобок и точки с запятой от одной инструкции к другой).И в этом случае, для выражений вычислений конструктора, возможна только сортировка присваиваний.

Поэтому, пожалуйста, не могли бы вы мне ответить:

1) Правильно ли сделан мой вывод?(относительно вычислительных выражений и конструктора для типов).

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

Но компилятор все равно злится ...

Благодаряkvd Я понял, что у меня есть возможность сделать следующее:

type public MyType =
   val private myvar: int
   val private myvar2: string
   (* ...Some val declarations... *)
   new () = {
      (* The default ctor makes something *)
   }
   new (ctorpar: AnotherType) = 
      for i in ctorpar.ACollection do
         (* Something *)
      {
      myvar = 1;
      myvar2 = "Hello";
      }

Ну, извините, но это не помогает мне, потому что компилятор F # говорит мне это:

ObjectКонструкторы не могут напрямую использовать try / with и try / finally до инициализации объекта.Это включает в себя конструкторы, такие как «для х в ...», которые могут разработать для использования этих конструкций.Это ограничение, наложенное Common IL.

ОК, если проблема что-то делает до инициализации объекта, и это звучит правильно, то давайте сделаем это после:

type public MyType =
   val mutable private myvar: int
   val mutable private myvar2: string
   (* ...Some val declarations... *)
   new () = {
      (* The default ctor makes something *)
   }
   new (ctorpar: AnotherType) = 
      {
      myvar = 1;
      myvar2 = "Hello";
      }
      then
      for i in ctorpar.ACollection do
         (* Something *)
         myvar <- 10

Опять разочарован неудачей:

Значение или конструктор 'myvar' не определены.

Что мне делать ????Кажется, что после того, как он не распознает элементы в моем классе, это кажется правильным, потому что это потребовало бы идентификатора, как при объявлении членов, использующих self или this ... здесь он не имеет собственной ссылки и, правильно, говорит мне: "Ты пытаешься получить то, что я не могу дать тебе !!!!!!"

Ответы [ 2 ]

13 голосов
/ 15 февраля 2011
  1. Нет, ваш вывод неверен.Фигурные скобки больше похожи на выражение построения записи, которое может содержать только назначения полей. Вы не можете делать ничего, кроме присвоения значений каждому полю в фигурных скобках.

  2. Вы можете поставить операторы перед назначением полей (то есть перед открывающей фигурной скобкой)как обычно.Если вы потом захотите выполнить другие операторы, вам нужно использовать ключевое слово then:

    type public MyType =
      val private myvar: int
      val private myvar2: string
    
      new () = 
        for i in 1 .. 10 do
          printfn "Before field assignments %i" i
        { myvar = 1; myvar2 = "test" } 
        then 
          for i in 1 .. 10 do
            printfn "After field assignments %i" i
    

Изменить

Относительно вашегоновый вопрос, вы можете использовать new (ctorpar:AnotherType) as this = ..., а затем this.myvar <- 10.

10 голосов
/ 16 февраля 2011

Ответ от kvb великолепен и дает вам всю запрашиваемую информацию: -).

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

type MyType(n:int, s:string) =
  do 
    // Run before fields initialized (they aren't accessible here)
    for i in 1 .. 10 do
      printfn "Before field assignments %i" i
  // Initialize fields (accessible from now on)
  let myvar = n
  let myvar2 = s
  do // Run after fields initialized - you can use them here
     for i in 1 .. 10 do
       printfn "After field assignments %i" i

  // You can add multiple constructors too:
  new() = MyType(0, "hi")
  member x.Foo = 0
...