链接&符号上的to_proc

时间:2016-01-03 17:47:49

标签: ruby symbols proc

众所周知,Rubyist import android.content.Context; import android.os.AsyncTask; import android.util.Pair; import android.widget.Toast; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.extensions.android.json.AndroidJsonFactory; import com.google.api.client.googleapis.services.AbstractGoogleClientRequest; import com.google.api.client.googleapis.services.GoogleClientRequestInitializer; import java.io.IOException; class SendRegisterInfo extends AsyncTask<Pair<Context, String>, Void, String> { private static MyApi myApiService = null; private Context context; @Override protected String doInBackground(Pair<Context, String>... params) { if(myApiService == null) { // Only do this once MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null) // options for running against local devappserver // - 10.0.2.2 is localhost's IP address in Android emulator // - turn off compression when running against local devappserver .setRootUrl("http://10.0.2.2:8080/_ah/api/") .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() { @Override public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException { abstractGoogleClientRequest.setDisableGZipContent(true); } }); // end options for devappserver myApiService = builder.build(); } context = params[0].first; String name = params[0].second; try { return myApiService.sayHi(name).execute().getData(); } catch (IOException e) { return e.getMessage(); } } @Override protected void onPostExecute(String result) { Toast.makeText(context, result, Toast.LENGTH_LONG).show(); } } 会在符号上调用&,所以

to_proc

相当于

[:a, :b, :c].map(&:to_s)

假设我想在[:a, :b, :c].map { |e| e.to_s } # => ["a", "b", "c"] 之后立即调用另一个方法,这两个实现将起作用:

to_s

我的问题是,有没有办法将[:a, :b, :c].map { |e| e.to_s.upcase } [:a, :b, :c].map(&:to_s).map(&:upcase) &调用链接在一个参数中?类似的东西:

Symbol#to_proc

谢谢!

6 个答案:

答案 0 :(得分:5)

您需要提前定义一些方法,但这将具有普遍性。你可以这样做:

class Symbol
  def * other
    ->x{x.send(self).send(other)}
  end
end

[:a, :b, :c].map(&:to_s * :upcase)
[:a, :b, :c].map(&:to_s * :capitalize)
...

我选择了*作为功能组合的方法。

如果您认为可以使用第三个符号,则可以定义如下:

class Proc
  def * other
    ->x{call(x).send(other)}
  end
end

答案 1 :(得分:4)

如果您只是这样做:

%i[a b c].map { |e| e.to_s.upcase }

然后只需使用该块并继续处理更重要的事情。如果您真的在进行一系列可枚举的调用,并且发现这些块太过嘈杂:

%i[a b c].map { |e| e.to_s.upcase }.some_chain_of_enumerable_calls...
然后你可以把你的逻辑扔进一个lambda来帮助清理外观:

to_s_upcase = lambda { |e| e.to_s.upcase }
%i[a b c].map(&to_s_upcase).some_chain_of_enumerable_calls...

或将其扔进方法并说:

%i[a b c].map(&method(:to_s_upcase)).some_chain_of_enumerable_calls...

无论哪种方式,你都会给你的一些逻辑提供一个名称(几乎所有&:symbol都在为你做),使代码更易读,更容易理解。在to_s.upcase的特定情况下,这有点毫无意义,但是当块变大时,这些方法非常有用。

答案 2 :(得分:4)

所以只是为了好玩(并且为了证明几乎任何东西都可以在ruby中进行一些努力)我们可以在Symbol上定义一个方法(我们称之为{{1} })提供此功能和更多

Symbol#chain

然后可以这样调用

class Symbol
  def proc_chain(*args)
    args.inject(self.to_proc) do |memo,meth|
      meth, *passable_args = [meth].flatten
      passable_block = passable_args.pop if passable_args.last.is_a?(Proc)
      Proc.new do |obj|
        memo.call(obj).__send__(meth,*passable_args,&passable_block)
      end
    end
  end
  alias_method :chain, :proc_chain
end

甚至可以单独使用

[:a, :b, :c].map(&:to_s.chain(:upcase))
#=> ["A","B","C"]
# Or with Arguments & blocks
[1,2,3,4,5].map(&:itself.chain([:to_s,2],:chars,[:map,->(e){ "#{e}!!!!"}]))
#=>  => [["1!!!!"], ["1!!!!", "0!!!!"], ["1!!!!", "1!!!!"],
#        ["1!!!!","0!!!!", "0!!!!"], ["1!!!!", "0!!!!", "1!!!!"]]

答案 3 :(得分:3)

虽然我们正在使用语法,但使用to_proc方法对猴子修补数组怎么样?

class Array
  def to_proc
    return :itself.to_proc if empty?
    ->(obj) { drop(1).to_proc.call(first.to_proc.call(obj)) }
  end
end

["foo", "bar", "baz"].map(&[:capitalize, :swapcase, :chars, ->a{ a.join("-") }])
# => ["f-O-O", "b-A-R", "b-A-Z"]

在repl.it上查看:https://repl.it/JS4B/1

答案 4 :(得分:1)

无法使用符号链接到proc。

但是,你可以将一个方法修补到你要映射的类上,然后调用它。

vector<A>

答案 5 :(得分:0)

我很惊讶没有人提到 Proc#<<Proc#>>

[:a, :b, :c].map(&(:to_s.to_proc << :upcase.to_proc))
# => ["A", "B", "C"]
[:a, :b, :c].map(&(:upcase.to_proc >> :to_s.to_proc))
# => ["A", "B", "C"]

参考:https://ruby-doc.org/core-2.7.2/Proc.html#method-i-3C-3C