Как написать функцию, где аргумент является типом, а не типизированным значением? - PullRequest
3 голосов
/ 16 марта 2010

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

Enum.Parse(typeof<FontStyle>,"Bold") |> unbox<FontStyle>

но сейчас я хочу написать функцию, где тип и строка являются параметрами. Лучшее, что я могу написать:

> let s2e (_: 'a) s = Enum.Parse(typeof<'a>,s) |> unbox<'a>;;
val s2e : 'a -> string -> 'a
> s2e FontStyle.Regular "Bold";;
val it : FontStyle = Bold

Можно ли написать что-то подобное, но с самим типом в качестве первого аргумента?

Ответы [ 2 ]

4 голосов
/ 16 марта 2010

Функция должна принимать параметр одного типа, который будет типом возвращаемого перечисления. Однако вам не нужно указывать тип, используя «поддельный» параметр, который нигде не используется в коде - вы можете указать фактический параметр типа при вызове функции, используя ту же запись, что и, например, при вызове defaultof<SomeType> ,

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

> let parseEnum<´a> s = Enum.Parse(typeof<´a>,s) |> unbox<´a>;; 
val parseEnum : string -> ´a

При вызове функции вам необходимо явно указать тип:

> parseEnum<FontStyle> "Bold";; 
val it : FontStyle = Bold

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

1 голос
/ 16 марта 2010

Томас ответил хорошо. Кроме того, обратите внимание, что вы можете применить ограничения F # enum, чтобы предотвратить использование бессмысленных параметров типа:

let parseEnum<'t,'u when 't:enum<'u>> s = System.Enum.Parse(typeof<'t>, s) :?> 't
(parseEnum "Class" : System.AttributeTargets)

Теперь вызов (parseEnum "Test" : int) не удастся во время компиляции, поскольку int не является перечислением.

EDIT

Поскольку мы на самом деле ничего не делаем с базовым типом 'u, нам не нужна полная мощность ограничений перечисления F #, как указывает ssp в комментарии. Это проще в использовании, потому что он имеет только один тип параметра:

let parseEnum<'t when 't :> System.Enum and 't : struct> s =
  System.Enum.Parse(typeof<'t>, s) :?> 't

Обратите внимание, что ограничение struct не позволяет использовать System.Enum в качестве аргумента типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...