#generics #f#
#дженерики #f#
Вопрос:
Почему следующий код не компилируется? Это ошибка компилятора или особенность языка? Каков наилучший обходной путь?
type A() as this =
let a = this.GetTypedObject<int>() // a
let b = this.GetTypedObject<string>() // b
member this.GetTypedObject<'T>() =
Unchecked.defaultof<'T>
Не проверено.defaultof<‘T> используется только для примера, вместо этого можно использовать вызов любой функции или конструктора.
Компилятор сообщает, что код становится менее универсальным в строке (a) и отказывается компилировать строку (b). Я не могу дать точные сообщения компилятора, потому что у меня они на русском :).
Превращение метода GetTypedObject() в привязку let и удаление <‘T> приводит к другому предупреждению компилятора, которое мне тоже не нравится. Единственный способ, который я нашел, это переместить GetTypedObject<‘T>() в базовый класс и сделать его общедоступным. Заранее спасибо…
Ответ №1:
Обратите внимание, что вы можете просто добавить аннотацию типа, чтобы исправить это:
type A() as this =
let a = this.GetTypedObject<int>() // a
let b = this.GetTypedObject<string>() // b
member this.GetTypedObject<'T>() : 'T =
//^^^^
Unchecked.defaultof<'T>
Сначала считываются подписи элементов, затем все тела let и member, когда дело доходит до порядка вывода типа. Ввод возвращаемого типа в подпись объявления делает его видимым для lets.
Комментарии:
1. Спасибо. Не мог представить, что решение может быть таким простым 🙂
Ответ №2:
Поскольку вывод типа выполняется сверху вниз, он обнаруживает . (Как указывает Брайан, элементы считываются перед GetTypedObject
возврат int
еще до того, как достигнет определения метода, и обнаруживает, что он должен быть универсальным let
привязками…и для этого есть более простое решение.)Я получаю следующую неприятную ошибку:
Использование функции ‘GetTypedObject’ не соответствует типу, выведенному в другом месте. Предполагаемый тип функции — Test.A -> Microsoft.FSharp.Core.unit -> ‘a. Тип функции, необходимой на данном этапе использования, — Test.A -> Microsoft.FSharp.Core.unit -> ‘a Эта ошибка может быть вызвана ограничениями, связанными с универсальной рекурсией в коллекции ‘let rec’ или в группе классов. Рассмотрите возможность предоставления полной подписи типа для целевых объектов рекурсивных вызовов, включая аннотации типов как для аргументов, так и для возвращаемых типов.
Если использование появляется после определения метода, оно работает.
type A() =
member this.GetTypedObject<'T>() =
Unchecked.defaultof<'T>
member this.Test() =
let a = this.GetTypedObject<int>() // a
let b = this.GetTypedObject<string>() // b
()
Вот обходной путь:
type A() =
let getTypedObject() = Unchecked.defaultof<_>
let a : int = getTypedObject() // a
let b : string = getTypedObject() // b
member this.GetTypedObject<'T>() : 'T = getTypedObject()
Комментарии:
1. Большое спасибо! Для меня сработало как по волшебству.