- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
使用 open array parameters
将数组(动态或静态)传递给方法/过程/函数, 声明可以如下所示:
procedure WorkWithArray( const anArray : array of Integer);
(* or procedure WorkWithArray( var anArray : array of Integer); *)
var
i : Integer;
begin
for i := Low(anArray) to High(anArray) do
begin
// Do something with the "open array" anArray
WriteLn(anArray[i]);
end;
end;
...
var
staticArray : array[0..2] of Integer;
dynArray : array of integer;
dynArrayG : TArray<Integer>;
begin
SetLength(dynArray,10);
SetLength(dynArrayG,10);
WorkWithArray(staticArray); // Using a static array
WorkWithArray(dynArray); // Using a dynamic array
WorkWithArray(dynArrayG); // Using a dynamic generic array
...
end;
像这样传递数组是整个 Delphi RTL 中非常常见的习惯用法,包括一些用于处理数据数组的非常优化的函数/过程。
<小时/>假设我们需要使用数组的子范围调用WorkWithArray
。然后我们可以使用内在的 Slice()
功能。
首先没有偏移量,从第一个索引开始:
Type
// Helper declarations
TIntLongArray = array[0..MaxInt div SizeOf(Integer) - 1] of integer;
PIntLongArray = ^TIntLongArray;
WorkWithArray(Slice(staticArray,2)); // No type cast needed for static arrays
WorkWithArray(Slice(PIntLongArray(@dynArray)^,2));
WorkWithArray(Slice(PIntLongArray(@dynArrayG)^,2));
注意:动态数组不能直接放入 Slice()
函数中, 请参阅"Slice does not work with dynamic arrays"
。 因此必须使用类型转换的解决方法。
如果我们想要使用不从第一个元素开始的子范围怎么办?
也可行:
WorkWithArray(Slice(PIntLongArray(@staticArray[1])^,2));
WorkWithArray(Slice(PIntLongArray(@dynArray[1])^,2));
WorkWithArray(Slice(PIntLongArray(@dynArrayG[1])^,2));
注意:偏移量和切片的总和不得超过数组的元素数。
<小时/>I know that using Copy(myArray,x1,x2) could be used in cases where the input is declared as a const, but this will make a copy of the the array, and is ineffiecient for large arrays. (With risk of stack overflow as well).
最后,我的问题:
虽然这演示了一种使用起始索引和长度说明符通过引用传递数组子范围的方法, 看起来有点尴尬。 有更好的选择吗?如果有的话如何选择?
最佳答案
已更新请参阅泛型解决方案的一些内容。
这是一个替代方案,它将偏移量所需的类型转换封装在函数内,该函数驻留在声明为类函数的高级记录中。除了隐藏类型转换之外,还根据数组的高索引检查偏移量的范围。
如果需要,可以添加更多类型。
Type
SubRange = record
Type
TIntLongArray = array[0..MaxInt div SizeOf(Integer) - 1] of integer;
PIntLongArray = ^TIntLongArray;
TByteLongArray = array[0..MaxInt div SizeOf(Byte) - 1] of Byte;
PByteLongArray = ^TByteLongArray;
class function Offset( const anArray : array of Integer;
offset : Integer) : PIntLongArray; overload; static;
class function Offset( const anArray : array of Byte;
offset : Integer) : PByteLongArray; overload; static;
// ToDo: Add more types ...
end;
class function SubRange.Offset(const anArray : array of Integer;
offset : Integer): PIntLongArray;
begin
Assert(offset <= High(anArray));
Result := PIntLongArray(@anArray[offset]);
end;
class function SubRange.Offset(const anArray : array of Byte;
offset : Integer): PByteLongArray;
begin
Assert(offset <= High(anArray));
Result := PByteLongArray(@anArray[offset]);
end;
注意:偏移量和切片的总和不得超过数组的元素数。
调用示例:
WorkWithArray( Slice(SubRange.Offset(staticArray,1)^,2));
WorkWithArray( Slice(SubRange.Offset(dynArray,1)^,2));
WorkWithArray( Slice(SubRange.Offset(dynArrayG,1)^,2));
虽然这看起来更好,但我仍然不相信这是最佳解决方案。
<小时/>更新
在编写上述解决方案时,我的最终目标是泛型解决方案。
这是一个利用匿名方法和泛型来实现 Slice(anArray,startIndex,Count)
的答案。可用于静态和动态数组的方法。
直接的泛型解决方案将依赖于在每个使用它的地方关闭范围检查,这不是一个很好的解决方案。原因是SizeOf(T)
无法用于声明最大大小的静态数组类型:
TGenericArray = array[0..MaxInt div SizeOf(T) - 1] of T; // SizeOf(T) not resolved
所以我们必须使用:
TGenericArray = array[0..0] of T;
相反。当索引 > 0 时,这会触发范围检查。
解决方案
但是这个问题可以通过另一种策略来解决,callbacks
或者更现代的术语是 Inversion of Control
(国际奥委会)或Dependeny Injection
(DI)。这个概念最好的解释是“不要调用我,我们调用你”。
我们不使用直接函数,而是将操作代码作为匿名方法与所有参数一起传递。现在范围检查问题包含在 Slice<T>
中框架。
Slice<Integer>.Execute(
procedure(const arr: array of Integer)
begin
WriteLn(Math.SumInt(arr));
end, dArr, 2, 7);
<小时/>
unit uGenericSlice;
interface
type
Slice<T> = record
private
type
PGenericArr = ^TGenericArr;
TGenericArr = array [0..0] of T;
public
type
TConstArrProc = reference to procedure(const anArr: array of T);
class procedure Execute( aProc: TConstArrProc;
const anArray: array of T;
startIndex,Count: Integer); static;
end;
implementation
class procedure Slice<T>.Execute(aProc: TConstArrProc;
const anArray: array of T; startIndex, Count: Integer);
begin
if (startIndex <= 0) then
aProc(Slice(anArray, Count))
else
begin
// The expression PGenericArr(@anArray[startIndex]) can trigger range check error
{$IFOPT R+}
{$DEFINE RestoreRangeCheck}
{$R-}
{$ENDIF}
Assert((startIndex <= High(anArray)) and (Count <= High(anArray)-startIndex+1),
'Range check error');
aProc(Slice(PGenericArr(@anArray[startIndex])^, Count));
{$IFDEF RestoreRangeCheck}
{$UNDEF RestoreRangeCheck}
{$R+}
{$ENDIF}
end;
end;
end.
以下是一些示例用例:
program ProjectGenericSlice;
{$APPTYPE CONSOLE}
uses
Math,
uGenericSlice in 'uGenericSlice.pas';
function Sum(const anArr: array of Integer): Integer;
var
i: Integer;
begin
Result := 0;
for i in anArr do
Result := Result + i;
end;
procedure SumTest(const arr: array of integer);
begin
WriteLn(Sum(arr));
end;
procedure TestAll;
var
aProc: Slice<Integer>.TConstArrProc;
dArr: TArray<Integer>;
mySum: Integer;
const
sArr: array [1 .. 10] of Integer = (
1,2,3,4,5,6,7,8,9,10);
begin
dArr := TArray<Integer>.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
aProc :=
procedure(const arr: array of Integer)
begin
WriteLn(Sum(arr));
end;
// Test predefined anonymous method
Slice<Integer>.Execute( aProc, dArr, 2, 7);
// Test inlined anonymous method
Slice<Integer>.Execute(
procedure(const arr: array of Integer)
begin
WriteLn(Sum(arr));
end, dArr, 2, 7);
// Test call to Math.SumInt
Slice<Integer>.Execute(
procedure(const arr: array of Integer)
begin
WriteLn(Math.SumInt(arr));
end, dArr, 2, 7);
// Test static array with Low(sArr) > 0
Slice<Integer>.Execute(
procedure(const arr: array of Integer)
begin
WriteLn(Sum(arr));
end, sArr, 3 - Low(sArr), 7);
// Using a real procedure
Slice<Integer>.Execute(
SumTest, // Cannot be nested inside TestAll
dArr, 2, 7);
// Test call where result is passed to local var
Slice<Integer>.Execute(
procedure(const arr: array of Integer)
begin
mySum := Math.SumInt(arr);
end, dArr, 2, 7);
WriteLn(mySum);
end;
begin
TestAll;
ReadLn;
end.
关于arrays - 通过带有起始和长度说明符的引用传递静态/动态数组的切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15993428/
我得到以下声明: // file MadaPacket.h class MadaPacket { // .... public: inline static bool word_is_header
目录 1.语法 2.关键词decltype 1.语法 decltype ( 实体 ) (1) (C++11 起) decltype
由于某些原因,我一直认为演绎指南必须相同noexcept -它们所引用的构造函数的性质。例如: template struct clazz { clazz(const T &) noexcep
我不确定成员 var isMouseOverYard 的正确访问说明符。在代码片段中,我没有从 House 继承的计划。选项 1 与基类更一致(如果我要从任一类继承,我可以检查鼠标是否在对象/院子上)
我可以声明 foo(const T& var) 这样我就知道 var 不会被改变。 指针的等效格式为 foo(const T* var)? 过去我尝试过那些,与 iterator/const_iter
我已经为这个问题搜索了几个小时,但仍然无法解决。 #include using namespace std; enum color { brown, green, orange, red, yell
我有用户定义的数据类型 typedef Unsigned int8 COMMAND_TYPE[6]; 现在我有类似的功能 ConnectCommand(COMMAND_TYPE const comm
说明符 %[^s] 有什么用? s 是一个变量。 在什么情况下我可以使用这个说明符? 最佳答案 scanf 的 %[ 格式说明符将匹配一系列字符,这些字符与 [ 和 ]< 之间列出的字符相匹配。如果第
#include int main() { char a[8]; printf("%d\n",a) ; return 0; } 对于上面的代码,输出是这
很抱歉这个“另一个”sscanf 问题,但我无法通过实验找到任何解决方案。 这是一个字符串,我想解析并提取 2 个由“:”分隔的子字符串: char *str = "tag:R123:P1234";
所以我在维基百科的一篇文章(粗略翻译)中遇到了以下定义: Modifier (programming) - element of source code being a phrase of given
[basic.link]/6 (我的重点): The name of a function declared in block scope and the name of a variable dec
我正在尝试定义我自己的数据类型(称为 sfloat),它类似于 float ,但使用不同数量的尾数位和指数位以更好地适应我的数据范围和精度。目标是定义一种新的数据类型,可以替代现有应用程序中的 flo
请看下面的代码: #include struct A { A(int, int) {} }; struct tag {}; template struct is_noexcept { st
如果这是一个无知的问题,请原谅我,但我仍在思考何时以及如何使用 constexpr 说明符。 (使用 msvc 14 编译)。我正在研究一个简单的基类,它允许您将任意对象包装到“constexpr 对
考虑以下函数: // Declaration in the .h file class MyClass { template void function(T&& x) const; }; /
以下面的示例代码为例: void test(const Item& item = Item()) { ... } 假设一旦 item 被传递给函数,this 就不能抛出。 问题是:函数应该标记为
我听说 noexcept 关键字更像是“它永远不应该抛出异常”而不是“它不会”。 如果我不确定是否抛出异常,我认为使用 noexcept 关键字不是很好,但是 noexcept 关键字有时
最近,我在阅读API of boost::optional 时发现: T const& operator *() const& ; T& operator *() & ; T&&
如果覆盖 ToString在一个类型中 type TestMe ()= override __.ToString() = null 然后我通过 "%A" 输出它说明符 printfn "*%A
我是一名优秀的程序员,十分优秀!