我正试图让jQuery风格的函数链接在我的脑海中.我的意思是:
var e = f1('test').f2().f3();
Run Code Online (Sandbox Code Playgroud)
我有一个例子可以工作,而另一个没有.我会发布以下内容.我总是想学习第一个原理的基本原理,以便我可以在它之上构建.到目前为止,我对链接的工作方式只有一个粗略而宽松的理解,而且我遇到了一些我无法智能排除故障的错误.
我知道的:
这个例子有效:
var one = function(num){
this.oldnum = num;
this.add = function(){
this.oldnum++;
return this;
}
if(this instanceof one){
return this.one;
}else{
return new one(num);
}
}
var test = one(1).add().add();
Run Code Online (Sandbox Code Playgroud)
但是这个没有:
var gmap = function(){
this.add = function(){
alert('add');
return this;
}
if(this instanceof gmap) {
return this.gmap;
} else{
return new gmap();
}
}
var test = gmap.add();
Run Code Online (Sandbox Code Playgroud) 我发现这个方法在python中链接,但即使有了它我也无法理解Python中的方法链接.
这里的目标是两个:解决编码问题并理解方法链(考虑到我仍然没有100%对callables有信心).
直到问题定义.
我想要一个有两个方法的类:一个设置object ='line'的参数,另一个设置覆盖'bar'.
这是我到目前为止所得到的:
class foo():
def __init__(self, kind=None):
self.kind = kind
def __call__(self, kind=None):
return foo(kind=kind)
def my_print(self):
print (self.kind)
def line(self):
return self(kind='line')
def bar(self):
return self(kind='bar')
Run Code Online (Sandbox Code Playgroud)
可悲的是,通过这段代码,我可以实现我的目标
a = foo()
a.bar().line().bar().bar().line().my_print()
Run Code Online (Sandbox Code Playgroud)
但是我希望通过编写这段代码来获得相同的结果
a = foo()
a.bar.line.bar.bar.line.my_print()
Run Code Online (Sandbox Code Playgroud)
我该如何实现这一目标?我想我定义__call__方法的方法有点不对劲.在此先感谢您的帮助.
jQuery让我链接方法.我还记得在PHP中看到相同的内容所以我写了这个:
class cat {
function meow() {
echo "meow!";
}
function purr() {
echo "purr!";
}
}
$kitty = new cat;
$kitty->meow()->purr();
Run Code Online (Sandbox Code Playgroud)
我不能让链条起作用.它会在喵喵之后产生致命错误.
所以我有以下代码:
// Learn more about F# at http://fsharp.net
open System
open System.Linq
open Microsoft.FSharp.Collections
let a = [1; 2; 3; 4; 54; 9]
let c = a |> List.map(fun(x) -> x*3) |> List.filter(fun(x) -> x > 10)
let d = a.Select(fun(x) -> x*3).Where(fun(x) -> x > 10)
for i in c do
Console.WriteLine(i)
for i in d do
Console.WriteLine(i)
Run Code Online (Sandbox Code Playgroud)
两者似乎做同样的事情,但我看到的大多数F#例子都使用了|>管道运算符,而我更习惯于方法链接(ala C#Linq).后者也稍微短一些,虽然稍微嘎吱作响.目前我正在使用C#Linq语法,但这更多是习惯/惯性而不是任何真正的设计决策.
是否有任何我应该了解的考虑因素,或者它们基本相同?
编辑:另一个考虑因素是管道语法比Linq语法明显更"嘈杂":我正在做的操作(例如"map")非常短而且是小写的,而每一个前面都有这个巨大的"|>列出"除了使它更长时间分散注意力远离微小的小写方法名称.甚至StackOverflow的语法高亮显示也突出了错误(不相关)的事情.无论是那个还是我都不习惯它.
当然,不是在可读性方面,因为您总是可以将单独的方法安排到单独的行中.相反,无论出于何种原因,将过多的方法链接在一起是危险的吗?我主要使用方法链来节省宣布单个一用变量的空间,传统上使用返回方法而不是修改调用者的方法.除了字符串方法,那些我有点无情地链.无论如何,我有时担心在一行中使用异常长的方法链的影响.
假设我需要根据某人的用户名更新一个项目的值.不幸的是,检索正确用户的最短方法看起来如下所示.
SPWeb web = GetWorkflowWeb();
SPList list2 = web.Lists["Wars"];
SPListItem item2 = list2.GetItemById(3);
SPListItem item3 = item2.GetItemFromLookup("Armies", "Allied Army");
SPUser user2 = item2.GetSPUser("Commander");
SPUser user3 = user2.GetAssociate("Spouse");
string username2 = user3.Name;
item1["Contact"] = username2;
Run Code Online (Sandbox Code Playgroud)
一个2或3的所有东西只持续一次通话,所以我可能会将其压缩为以下(这也让我摆脱了一个多余的1):
SPWeb web = GetWorkflowWeb();
item["Contact"] = web.Lists["Armies"]
.GetItemById(3)
.GetItemFromLookup("Armies", "Allied Army")
.GetSPUser("Commander")
.GetAssociate("Spouse")
.Name;
Run Code Online (Sandbox Code Playgroud)
不可否认,当它在一条线上并且当你有int.Parse(ddlArmy.SelectedValue.CutBefore(";#", false))而不是时,它看起来要长得多3.然而,这是这些链的平均长度之一,我可以很容易地预见到一些特别长的计数.排除可读性,对于这10个以上的方法链,我应该担心什么吗?或者使用非常长的方法链是否有害?
在Scala中,我倾向于使用val赋值在许多较小的表达式上编写大型链式表达式.在我的公司,我们已经为这种类型的代码改进了一种风格.这是一个完全人为的例子(想法是显示一个包含大量链接调用的表达式):
import scala.util.Random
val table = (1 to 10) map { (Random.nextInt(100), _) } toMap
def foo: List[Int] =
(1 to 100)
.view
.map { _ + 3 }
.filter { _ > 10 }
.flatMap { table.get }
.take(3)
.toList
Run Code Online (Sandbox Code Playgroud)
Daniel Spiewak的Scala风格指南(pdf),我一般都喜欢,它表明链式方法调用中的前导点符号可能不好(参见doc:Method Invocation/Higher-Order Functions),尽管它不包括多行表达式直接这样.
是否有另一种更为接受/惯用的方式来编写上述函数foo?
更新:2011年6月28日
下面有很多很棒的答案和讨论.似乎没有100%"你必须这样做"答案,所以我将接受最受欢迎的答案,这是目前的理解方法.就个人而言,我认为我现在要坚持使用前导符号,并接受随之而来的风险.
这绝对是主观的,但我想尽量避免它变得有争议.我认为如果人们适当地对待它可能是一个有趣的问题.
在我最近的几个项目中,我曾经实现过长代理链是常见的架构.
可能经常遇到双重委托链:
bool Exists = Env->FileSystem->FileExists( "foo.txt" );
Run Code Online (Sandbox Code Playgroud)
三重代表团并不罕见:
Env->Renderer->GetCanvas()->TextStr( ... );
Run Code Online (Sandbox Code Playgroud)
存在更高级别的代表团,但实际上很少.
在上述示例中,不执行NULL运行时检查,因为所使用的对象始终存在并且对于程序的运行是至关重要的并且在执行开始时被显式构造.基本上我曾经在这些情况下拆分委托链:
1)我重用通过委托链获得的对象:
{ // make C invisible to the parent scope
clCanvas* C = Env->Renderer->GetCanvas();
C->TextStr( ... );
C->TextStr( ... );
C->TextStr( ... );
}
Run Code Online (Sandbox Code Playgroud)
2)在使用之前,应该检查委托链中间某处的中间对象是否为NULL.例如.
clCanvas* C = Env->Renderer->GetCanvas();
if ( C ) C->TextStr( ... );
Run Code Online (Sandbox Code Playgroud)
我曾经通过提供代理对象来对抗案例(2),以便可以在非NULL对象上调用方法,从而产生empty结果.
我的问题是:
以下是我在做出选择时考虑的一些优缺点:
优点:
缺点:
我想知道长代表团的其他利弊.请根据有争议的观点提出你的推理和投票,而不是你对它的看法.
(不要与itertools.chain混淆)
我正在阅读以下内容:http: //en.wikipedia.org/wiki/Method_chaining
我的问题是:在python中实现方法链的最佳方法是什么?
这是我的尝试:
class chain():
def __init__(self, my_object):
self.o = my_object
def __getattr__(self, attr):
x = getattr(self.o, attr)
if hasattr(x, '__call__'):
method = x
return lambda *args: self if method(*args) is None else method(*args)
else:
prop = x
return prop
list_ = chain([1, 2, 3, 0])
print list_.extend([9, 5]).sort().reverse()
"""
C:\Python27\python.exe C:/Users/Robert/PycharmProjects/contests/sof.py
[9, 5, 3, 2, 1, 0]
"""
Run Code Online (Sandbox Code Playgroud)
一个问题是如果调用method(*args)修改self.o但不返回None.(然后我应该返回self或返回什么method(*args)返回).
有没有人有更好的方法来实现链接?可能有很多方法可以做到这一点.
我应该假设一个方法总是返回None …
只是想整理一个程序,并想知道是否有人可以在同一行上多次调用一个队列上的成员函数给我一些语法糖.
例如,更改:
queue<int> q;
q.push(0);
q.push(1);
Run Code Online (Sandbox Code Playgroud)
类似于:
q.(push(0), push(1));
//or
q.push(0).push(1);
Run Code Online (Sandbox Code Playgroud)
我知道它看起来有点荒谬,并不实用.但是,如果我想缩短这样的一小部分代码,是否可以选择这样做?从我到目前为止所读到的内容来看,只有在函数具有非void返回值时才能链接方法.
当然,这是一个选项:
q.push(0); q.push(1);
Run Code Online (Sandbox Code Playgroud)
但我试图避免在q那里两次.再次......语法糖:)
这里的目标不是初始化,而是压缩对象/容器在代码块中生成的次数.我引用队列的原因是因为它是动态的.
c++ member-functions syntactic-sugar function-calls method-chaining
所以...在JavaScript中乱搞一个对我来说很新的想法,让Object的方法返回它们是方法的Object; 这导致了可链接性.我的问题是:这怎么有用?我把它扔在一起测试基本工作:
<script>
MathChain = function()
{
this.pass = function()
{
this.multiply = eval(arguments.join('*'));
this.add = eval(arguments.join('+'));
return this;
}
}
m = new MathChain().pass(5, 10, 20).multiply; // 1000
a = new MathChain().pass(5, 10, 20).add; // 35
</script>
Run Code Online (Sandbox Code Playgroud)
这显然不是一个恶意高效的实例,人们会使用这个概念,所以你能指出我做的事情吗(除了jQuery,请)?
method-chaining ×10
c++ ×2
chaining ×2
javascript ×2
methods ×2
python ×2
c# ×1
c#-to-f# ×1
callable ×1
coding-style ×1
delegation ×1
f# ×1
filter ×1
map ×1
object ×1
php ×1
scala ×1
syntax ×1