Có, bạn có thể. Bí quyết là sử dụng các phương thức đệ quy đuôi, để khung ngăn xếp cục bộ chứa tham chiếu duy nhất cho cá thể Stream
. Vì phương pháp này là đệ quy đuôi, tham chiếu cục bộ cho đầu Stream
trước đó sẽ bị xóa khi nó đệ quy gọi chính nó, do đó cho phép GC thu thập sự bắt đầu của số Stream
khi bạn thực hiện.
Welcome to Scala version 2.9.0.r23459-b20101108091606 (Java HotSpot(TM) Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import collection.immutable.Stream
import collection.immutable.Stream
scala> import annotation.tailrec
import annotation.tailrec
scala> @tailrec def last(s: Stream[Int]): Int = if (s.tail.isEmpty) s.head else last(s.tail)
last: (s: scala.collection.immutable.Stream[Int])Int
scala> last(Stream.range(0, 100000000))
res2: Int = 99999999
Ngoài ra, bạn phải đảm bảo rằng điều bạn chuyển đến phương thức last
ở trên chỉ có một tham chiếu trên chồng. Nếu bạn lưu trữ Stream
vào biến hoặc giá trị cục bộ, nó sẽ không được thu thập rác khi bạn gọi phương thức last
, vì đối số của nó không phải là tham chiếu duy nhất còn lại đến Stream
. Mã bên dưới hết bộ nhớ.
scala> val s = Stream.range(0, 100000000)
s: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> last(s)
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at sun.net.www.ParseUtil.encodePath(ParseUtil.java:84)
at sun.misc.URLClassPath$JarLoader.checkResource(URLClassPath.java:674)
at sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:759)
at sun.misc.URLClassPath.getResource(URLClassPath.java:169)
at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at scala.tools.nsc.Interpreter$Request$$anonfun$onErr$1$1.apply(Interpreter.scala:978)
at scala.tools.nsc.Interpreter$Request$$anonfun$onErr$1$1.apply(Interpreter.scala:976)
at scala.util.control.Exception$Catch.apply(Exception.scala:80)
at scala.tools.nsc.Interpreter$Request.loadAndRun(Interpreter.scala:984)
at scala.tools.nsc.Interpreter.loadAndRunReq$1(Interpreter.scala:579)
at scala.tools.nsc.Interpreter.interpret(Interpreter.scala:599)
at scala.tools.nsc.Interpreter.interpret(Interpreter.scala:576)
at scala.tools.nsc.InterpreterLoop.reallyInterpret$1(InterpreterLoop.scala:472)
at scala.tools.nsc.InterpreterLoop.interpretStartingWith(InterpreterLoop.scala:515)
at scala.tools.nsc.InterpreterLoop.command(InterpreterLoop.scala:362)
at scala.tools.nsc.InterpreterLoop.processLine$1(InterpreterLoop.scala:243)
at scala.tools.nsc.InterpreterLoop.repl(InterpreterLoop.scala:249)
at scala.tools.nsc.InterpreterLoop.main(InterpreterLoop.scala:559)
at scala.tools.nsc.MainGenericRunner$.process(MainGenericRunner.scala:75)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:31)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Để tóm tắt:
- Sử dụng phương pháp đuôi-đệ quy
- Chú thích chúng như đuôi-đệ quy
- Khi bạn gọi cho họ, đảm bảo rằng lập luận của họ là tham khảo đến
Stream
EDIT:
Lưu ý rằng điều này cũng làm việc và không dẫn đến một trong số lỗi bộ nhớ:
scala> def s = Stream.range(0, 100000000)
s: scala.collection.immutable.Stream[Int]
scala> last(s)
res1: Int = 99999999
EDIT2:
Và trong trường hợp của
reduceLeft
mà bạn yêu cầu, bạn sẽ phải xác định một phương pháp helper với một tham số tích lũy cho kết quả.
Để giảmLeft, bạn cần một đối số tích lũy, mà bạn có thể đặt thành một giá trị nhất định bằng cách sử dụng đối số mặc định. Ví dụ đơn giản:
scala> @tailrec def rcl(s: Stream[Int], acc: Int = 0): Int = if (s.isEmpty) acc else rcl(s.tail, acc + s.head)
rcl: (s: scala.collection.immutable.Stream[Int],acc: Int)Int
scala> rcl(Stream.range(0, 10000000))
res6: Int = -2014260032
Mặc dù điều này không có cách nào trả lời câu hỏi của bạn, tôi thấy rằng cú pháp '# ::' cho luồng có thể đọc được nhiều hơn trên 'Stream.cons' –