我在阅读 PHP 手册(特别是 each() 函数)时遇到了以下警告:
Caution
Because assigning an array to another variable resets the original array's pointer, our example above would cause an endless loop had we assigned $fruit to another variable inside the loop.
还有一个例子:
<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');
reset($fruit);
while (list($key, $val) = each($fruit)) {
echo "$key => $val\n";
}
?>
好的。这说得通。但我决定做一个简单的测试:
<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');
foreach ($fruit as $key => $name) {
printf("[%s] => [%s]\n", $key, $name);
}
$fruit2 = $fruit;
echo current($fruit);
?>
结果符合预期:指针已重置。我的问题是指针是否仅在数组结束后才重置?
例如:
<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');
foreach ($fruit as $key => $name) {
printf("[%s] => [%s]\n", $key, $name);
}
reset($fruit);
next($fruit)."\n";
$fruit2 = $fruit;
echo current($fruit);
?>
指针保留在第二个数组元素 ('b' => 'banana') 中。
这种行为是语言的特征?
谢谢你,抱歉英语不好。
最佳答案
This behavior is characteristic of language?
PHP 数组中“指针”的含义与“指针”的一般含义(在 C/C++ 或其他允许程序员直接访问内存的语言中)不同。
PHP 中没有指针。 array数据类型在其包含的值列表内部保留一个游标。它被称为数组的内部指针,它被函数修改 reset() , next() , prev() , end() , each() 也许还有其他人。它可用于像这样遍历数组:
$array = array(1, 2, 3);
while (list($key, $val) = each($array)) {
echo($key.' => '.$val."\n");
}
没有可靠的方法使用 next() 迭代数组或 prev() 因为他们返回 FALSE当没有更多元素要迭代但它们也返回 FALSE 时当值 FALSE作为一个元素存储在数组中。
如果您只需要分析数组开头(或结尾)的几个项目,它们可能很有用。 F.e.假设我们有一个函数返回的整数数组,我们需要获取第一个不为零的值。
但是使用 foreach() 可以更轻松地实现这个目标:
$array = array(0, 0, 0, 2, 0, 1, 0, 3);
foreach ($array as $val) {
if ($val != 0) {
break;
}
}
echo($val); // prints "2"
或array_shift() :
$array = array(0, 0, 0, 2, 0, 1, 0, 3);
do {
$val = array_shift($array);
if ($val != 0) {
break;
}
} while(count($array));
echo($val); // prints "2"
The result is expected: the pointer has been reset. My question is if the pointer is reset only after the end of the array?
foreach() 的文档是错的。也许它在 PHP 3 和 PHP 4 上是正确的,但我认为自从引入 iterators 以来在 PHP 5 中 foreach() 的行为改变(变得更好)。
它说:
When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.
As foreach relies on the internal array pointer, changing it within the loop may lead to unexpected behavior.
一个简单的测试与这个陈述相矛盾:
$array = array(1, 3, 5, 7, 9);
foreach ($array as $val1) {
foreach ($array as $val2) {
echo('$val1='.$val1.'; $val2='.$val2.'; ');
}
echo("\n");
}
它工作没有问题。如果 foreach() 它不应该工作正在使用内部数组指针。它可能会创建指针的副本。
你也可以尝试使用current() , next() , prev()或 reset()在foreach()里面你会得到令人惊讶的,有时甚至是不一致的结果。
你最好使用foreach()遍历数组并且不以任何方式依赖内部指针。
函数reset()和 end()但是,当您需要获取数组的第一个和最后一个元素而不用担心键时,它们非常方便。
关于PHP 行为和数组指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30446546/
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio
我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。
假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje
这是针对我无法破坏的现有公共(public)API,但我确实希望对其进行扩展。目前,该方法采用字符串或符号或任何其他在作为第一个参数传递给send时有意义的内容我想添加发送字符串、符号等列表的功能。我可以只使用is_a吗?数组,但还有其他发送列表的方法,这不是很像ruby。我将调用列表中的map,所以第一个倾向是使用respond_to?:map。但是字符串也会响应:map,所以这行不通。 最佳答案 如何将它们全部视为数组?String的行为与仅包含String的Array相同:deffoo(obj,arg)[*arg].eac
我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject
>>a=5=>5>>b=a=>5>>b=4=>4>>a=>5如何将“b”设置为实际的“a”,以便在示例中,变量a也将变为4。谢谢。 最佳答案 classRefdefinitializeval@val=valendattr_accessor:valdefto_s@val.to_sendenda=Ref.new(4)b=aputsa#=>4putsb#=>4a.val=5putsa#=>5putsb#=>5当您执行b=a时,b指向与a相同的对象(它们具有相同的object_id).当你执行a=some_other_thing时,a将指向
defreverse(ary)result=[]forresult[0,0]inaryendresultendassert_equal["baz","bar","foo"],reverse(["foo","bar","baz"])这行得通,我想了解原因。有什么解释吗? 最佳答案 如果我使用each而不是for/in重写它,它看起来像这样:defreverse(ary)result=[]#forresult[0,0]inaryary.eachdo|item|result[0,0]=itemendresultendforainb基本上就
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它
以下测试中的第3个失败:specify{(0.6*2).shouldeql(1.2)}specify{(0.3*3).shouldeql(0.3*3)}specify{(0.3*3).shouldeql(0.9)}#thisonefails这是为什么呢?这是浮点问题还是ruby或rspec问题? 最佳答案 从rspec-2.1开始specify{(0.6*2).shouldbe_within(0.01).of(1.2)}在那之前:specify{(0.6*2).shouldbe_close(1.2,0.01)}