Ну, вам правильно пишет, надо указывать параметры шаблона явно:
function f1<T>: T := default(T);
begin
var a := f1<byte>;
end.
Тут уже выдаёт другую ошибку. Проблема в том что компилятор думает что вы сравниваете указатель на функцию f1 и типа byte оператором <. А затем сравниваете результат с ничем. Поэтому пишет что ожидалось выражение вместо ; то есть то с чем можно сравнить.
В этом случае нужно экранировать первый <, то есть поставить перед ним & (этот знак под семёркой в англ раскладке). Тогда компилятор не сможет считать < оператором сравнения, и всё скомпилируется правильно.
begin
var i:=1;
i.Println;
begin
var i:=2; // компилятор выдает ошибку
i.Print;
Inc(i);
i.Println
end;
i.Println
end.
Ошибка следующая: Внутриблочные переменные не могут иметь те же имена, что и переменные из блока верхнего уровня
А почему, собственно? Создавая Паскаль, Н.Вирт оглядывался на языки Algol-60/68, в разработке которых он принимал участие. В языке Algol любой блок begin ... end наделялся правом управлять памятью описанных в нем объектов программы. Описали переменную - можете пользоваться. Из блока вышли - все, переменная исчезла. Не то, чтобы ее скушал какой-то сборщик мусора - она отдавалась на нужды программы и могла быть отдана под какой-то иной объект в следующем блоке. Другими словами, локализация переменных в блоке была действительно локализацией. Коллизии имен не возникало, потому что вне блока его переменные не были видны, а внутри блока локальное объявление имело приоритет. И вот это программистское счастье Н.Вирт порушил “одной левой”, потребовав все объекты программы описывать в специальном разделе. В Паскале Н.Вирта вся требуемая память выделялась компилятором разово и статически. Зато эффективно. но… неудобно. В Turbo Pascal попытались поизвращаться и создали кошмарный механизм работы с управляемой памятью. В Delphi это дело подправили и появились нормальные динамические массивы.
Я не знаю, чем руководствовались разработчики PascalАВС.NET реализовав возможность описывать переменные посредством var в любом месте программы, и не обеспечив локализацию описанных переменных в блоке. Может быть, эффективностью программы? В самом деле, если использовать механизм динамической памяти, строгая локализация потребует при каждом входе в блок выделять память, а при выходе - освобождать. Представим себе переменную, описанную внутри составного оператора во вложенном цикле… Конечно, это все так, фантазия. Разработчики, если сочтут нужным, расскажут как оно на самом деле было. Но факт остается фактом: в PascalАВС.NET память в программной единице выделяется один раз, невзирая на местонахождение var. И, если переменная не инициализирована, компилятор не делает никаких “телодвижений”. Сама среда .NET при выделении памяти всегда производит инициализацию. С этой позиции, я думаю, понятно поведение кода, который привел @Bronislav
Нет ну “почему?” - понятно. В IL коде нету внутри-блочных переменных, они всегда описываются в начале подпрограммы как в старых паскалях. Другое дело - надо всё же чётко решить:
@Admin это нормально или всё же должно быть исправлено? Возможно надо больше настаивать на том что переменные надо всегда инициализировать, потому что так:
begin
loop 10 do
begin
var i: integer := 0;
writeln(i);
i += 1;
end;
end.
Зачем на этом настаивать специально? Любая переменная должна быть инициализирована перед первым обращением к ней - это основа какого угодно алгоритма. Если человеку вольно нарушать этот канон - ну, как говорится, “флаг ему в руки и трамвай навстречу” (не правда ли, я добрый?). Если он делает инициализацию явно - это уже стреляный воробей, а если полагается на особенности среды программирования, то это воробей желтоклювый, имеющий шанс после первого же выстрела стать воробьем дохлым.
static void Main(string[] args)
{
int i;
{
int i;
}
}
Локальная переменная или параметр с именем “i” нельзя объявить в данной области, так как это имя используется во включающей локальной области для определения локальной переменной или параметра
Не путайте operator explicit и as. .Cast выполняет именно as.
Разница в том - что as работает для классов-наследников друг-друга.
А operator explicit это обычная функция, посыпанная тонким слоем сахарка (то что её можно вызывать через real(i)). Она может быть перегружена (вроде даже экстенш-методом), но поэтому же - компилятор должно явно указать в IL коде какая перегрузка вызывается. Поэтому шаблонную функцию используя его не напишешь.
P.S. Да, вот через extensionmethod:
function operator explicit(self: System.Type): integer; extensionmethod;
begin
Result := self.GetHashCode;
end;
begin
var t := typeof(object);
integer(t).Print;
end.
Я не разбираюсь в классах, пока еще, просто взял пример из справки по Cast, там один в один, добавил вывод и оно выдало ошибку. То есть вывести через Print или Write эти элементы последовательности(?) нельзя. А как их вывести тогда, ну и написали бы в справке вывод, чтоб понятно было. Мне вот не понятно.