2013-11-28 3 views
10

TL; DR: il compilatore F # interpreta int in questo contesto come il int operator, come determined by Eugene Fotin e expanded upon by Gene Belitski. La soluzione migliore è utilizzare System.Int32.MaxValue o un alias di tipo univoco come descritto di seguito.F # int.MaxValue è "non un'espressione costante valida", ma System.Int32.MaxValue è?


Si consideri il seguente tipo di record:

type User = { 
    Username : string 
} 

voglio Username essere almeno tre caratteri, in modo da utilizzare l'attributo StringLength. Non esiste una durata massima, quindi ho impostato a int.MaxValue:

type User = { 
    [<StringLength(int.MaxValue, MinimumLength=3)>] 
    Username : string 
} 

Questo mi dà il seguente errore:

This is not a valid constant expression or custom attribute value.

Tutto è peachy se uso System.Int32 invece:

type User = { 
    [<StringLength(System.Int32.MaxValue, MinimumLength=3)>] 
    Username : string 
} 

Compilare anche se io alias int:

type User = { 
    [<StringLength(num.MaxValue, MinimumLength=3)>] 
    Username : string 
} 
and num = int 

o completamente qualificare il tipo:

type User = { 
    [<StringLength(Microsoft.FSharp.Core.int.MaxValue, MinimumLength=3)>] 
    Username : string 
} 

ho controllato la fonte # F e int is defined exactly as you would expect:

type int32 = System.Int32 
// Then, a few lines later… 
type int = int32 

Cosa sta succedendo? Supponevo che i tipi primitivi F # fossero intercambiabili con altri tipi nella maggior parte dei contesti, ma sembra che manchi qualcosa dal mio modello mentale.

risposta

11

Ecco come F # inferenza di tipo lavora in contesti diversi con differenti entità sintattiche coincidenza con lo stesso nome, che in caso di int può essere qualsiasi:

  • funzione int:'T->int del nome completo Microsoft.FSharp.Core.Operators.int
  • type int = int32 di nome completo Microsoft.FSharp.Core.int
  • type int<'Measure> = int del nome completo Microsoft.FSharp.Core.int<_>

Un modo per Demo Questa lavorazioni sarebbe il seguente scenario: se abbiamo appena entriamo

int;; 

in FSI ci arriveremo qualcosa come

val it : (int -> int) = <fun:[email protected]> 

in altre parole, si tratta di una funzione che non può hanno MaxValue proprietà associata con essa:

> int.MaxValue;; 

int.MaxValue;; 
----^^^^^^^^ 

... error FS0039: The field, constructor or member 'MaxValue' is not defined 

Lo stesso dicasi per int32 che, quando viene utilizzato in un contesto di espressione viene dedotto da FSI come solo un'altra funzione con la firma (int -> int32).

Ora, quando si tratta di

type num = int 

in questo contesto int viene dedotto essere un'abbreviazione nome tipo per System.Int32, così num è un tipo abbreviazione pure, ma ora denominare ambiguità non ha luogo, così num.MaxValue è dedotto esattamente quello che ci aspettiamo che sia, dando in FSI

> num.MaxValue;; 
val it : int = 2147483647 

Infine, quando si utilizza Microsoft.FSharp.Core.int si fa riferimento in modo esplicito per l'entità di tipo, non v'è alcuna posto per ambiguità, quindi funziona come previsto.

Torna al caso d'uso con parametro attributo - in questo contesto int viene trattato per tipo di inferenza come parte dell'espressione per fornire valore argomento, cioè come funzione, a meno che non si imposti esplicitamente o indirettamente un'altra interpretazione.

5

Sembra compilatore trattamento int nel parametro di un attributo come una funzione di conversione int.

+0

Hai ragione, ecco cosa sta succedendo. Mi chiedo perché sia ​​così? Qualcosa nella grammatica F #, immagino? –